mirror of
https://github.com/vector-im/element-call.git
synced 2026-10-16 23:45:50 +00:00
Let developers override the whole transport
The developer setting that overrode the LiveKit service URL becomes a JSON transport, so that a `url`-only or combined transport can be tested against a homeserver that does not advertise one yet. The settings modal shows each LiveKit room's role instead of a never-populated isLocal flag. Folds "Avoid null in transport dev setting" from the same PR. The setting feeds the SDK's transport option; the config fallback becomes a transport the host builds. Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org>
This commit is contained in:
committed by
Timo
co-authored by
Johannes Marbach
parent
f97dd2adab
commit
289260531b
@@ -83,7 +83,7 @@ import {
|
|||||||
cameraCodec,
|
cameraCodec,
|
||||||
cameraFramerate,
|
cameraFramerate,
|
||||||
cameraResolution,
|
cameraResolution,
|
||||||
customLivekitUrl,
|
customTransport,
|
||||||
echoCancellationSetting,
|
echoCancellationSetting,
|
||||||
matrixRTCMode as matrixRTCModeSetting,
|
matrixRTCMode as matrixRTCModeSetting,
|
||||||
noiseSuppressionSetting,
|
noiseSuppressionSetting,
|
||||||
@@ -823,7 +823,10 @@ export function rtcParticipationOptions(
|
|||||||
delegatedDelayedLeave: session.delegated_delayed_leave,
|
delegatedDelayedLeave: session.delegated_delayed_leave,
|
||||||
},
|
},
|
||||||
mediaQuality: config.media_quality,
|
mediaQuality: config.media_quality,
|
||||||
transportUrl: customLivekitUrl.value$.value ?? undefined,
|
transport: customTransport.value$.value ?? undefined,
|
||||||
fallbackTransportUrl: config.livekit?.livekit_service_url,
|
fallbackTransport: config.livekit && {
|
||||||
|
type: "livekit",
|
||||||
|
livekit_service_url: config.livekit.livekit_service_url,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
MatrixRTCMode,
|
MatrixRTCMode,
|
||||||
} from "@element-hq/matrixrtc-sdk";
|
} from "@element-hq/matrixrtc-sdk";
|
||||||
import type * as MatrixRTCSdk from "@element-hq/matrixrtc-sdk";
|
import type * as MatrixRTCSdk from "@element-hq/matrixrtc-sdk";
|
||||||
import { mockConfig } from "../utils/test";
|
import { exampleTransport, mockConfig } from "../utils/test";
|
||||||
|
|
||||||
// Mock url params hook to avoid environment-dependent snapshot churn.
|
// Mock url params hook to avoid environment-dependent snapshot churn.
|
||||||
vi.mock("../UrlParams", () => ({
|
vi.mock("../UrlParams", () => ({
|
||||||
@@ -232,10 +232,12 @@ describe("DeveloperSettingsTab", () => {
|
|||||||
const saveButton = screen.getByRole("button", { name: "Save" });
|
const saveButton = screen.getByRole("button", { name: "Save" });
|
||||||
await user.click(saveButton);
|
await user.click(saveButton);
|
||||||
expect(authenticateWithTransport).toHaveBeenCalledWith(
|
expect(authenticateWithTransport).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.objectContaining({
|
||||||
expect.anything(),
|
transport: { type: "livekit", url: "wss://example.livekit.valid" },
|
||||||
"wss://example.livekit.valid",
|
serverName: "hs",
|
||||||
"#testRoom",
|
roomId: "#testRoom",
|
||||||
|
role: "publisher",
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(customTransportSetting.getValue()).toEqual({
|
expect(customTransportSetting.getValue()).toEqual({
|
||||||
@@ -266,7 +268,7 @@ describe("DeveloperSettingsTab", () => {
|
|||||||
|
|
||||||
const saveButton = screen.getByRole("button", { name: "Save" });
|
const saveButton = screen.getByRole("button", { name: "Save" });
|
||||||
(authenticateWithTransport as Mock).mockImplementation(() => {
|
(authenticateWithTransport as Mock).mockImplementation(() => {
|
||||||
throw new Error("Invalid URL");
|
throw new Error("Failed to get SFU config");
|
||||||
});
|
});
|
||||||
await user.click(saveButton);
|
await user.click(saveButton);
|
||||||
expect(
|
expect(
|
||||||
@@ -276,9 +278,6 @@ describe("DeveloperSettingsTab", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add this test inside the describe("DeveloperSettingsTab", () => { block,
|
|
||||||
// after the custom transport tests:
|
|
||||||
|
|
||||||
describe("enable extended livekit logs", () => {
|
describe("enable extended livekit logs", () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
enableExtendedLivekitLogsSetting.setValue(false);
|
enableExtendedLivekitLogsSetting.setValue(false);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
type MatrixClient,
|
type MatrixClient,
|
||||||
} from "matrix-js-sdk";
|
} from "matrix-js-sdk";
|
||||||
import { logger } from "matrix-js-sdk/lib/logger";
|
import { logger } from "matrix-js-sdk/lib/logger";
|
||||||
|
import { type UnstableLivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
|
||||||
import {
|
import {
|
||||||
EditInPlace,
|
EditInPlace,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
@@ -173,17 +174,17 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
|||||||
enableExtendedLivekitLogsSetting,
|
enableExtendedLivekitLogsSetting,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [customTransportUpdateError, setCustomLivekitUrlUpdateError] = useState<
|
const [customTransportUpdateError, setCustomTransportUpdateError] = useState<
|
||||||
string | null
|
string | null
|
||||||
>(null);
|
>(null);
|
||||||
const [customTransport, setCustomTransport] = useSetting(
|
const [customTransport, setCustomTransport] = useSetting(
|
||||||
customTransportSetting,
|
customTransportSetting,
|
||||||
);
|
);
|
||||||
const [customTransportTextBuffer, setCustomLivekitUrlTextBuffer] = useState(
|
const [customTransportTextBuffer, setCustomTransportTextBuffer] = useState(
|
||||||
() => transportText(customTransport),
|
() => transportText(customTransport),
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCustomLivekitUrlTextBuffer(transportText(customTransport));
|
setCustomTransportTextBuffer(transportText(customTransport));
|
||||||
}, [customTransport]);
|
}, [customTransport]);
|
||||||
|
|
||||||
const [muteAllAudio, setMuteAllAudio] = useSetting(muteAllAudioSetting);
|
const [muteAllAudio, setMuteAllAudio] = useSetting(muteAllAudioSetting);
|
||||||
@@ -499,11 +500,7 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
|||||||
cancelButtonLabel={t("developer_mode.custom_transport.reset")}
|
cancelButtonLabel={t("developer_mode.custom_transport.reset")}
|
||||||
onSave={useCallback(
|
onSave={useCallback(
|
||||||
async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
|
async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
|
||||||
if (
|
if (roomId === undefined || customTransportTextBuffer === "") {
|
||||||
roomId === undefined ||
|
|
||||||
customTransportTextBuffer === "" ||
|
|
||||||
customTransportTextBuffer === null
|
|
||||||
) {
|
|
||||||
setCustomTransport(null);
|
setCustomTransport(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -511,36 +508,39 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
|||||||
try {
|
try {
|
||||||
const userId = client.getUserId();
|
const userId = client.getUserId();
|
||||||
const deviceId = client.getDeviceId();
|
const deviceId = client.getDeviceId();
|
||||||
|
const serverName = client.getDomain();
|
||||||
|
|
||||||
if (userId === null || deviceId === null) {
|
if (userId === null || deviceId === null || serverName === null) {
|
||||||
throw new Error("Invalid user or device ID");
|
throw new Error("Invalid user, device ID or server name");
|
||||||
}
|
}
|
||||||
await authenticateWithTransport(
|
const transport = JSON.parse(customTransportTextBuffer);
|
||||||
|
// Validate the transport by attempting to get a token for it
|
||||||
|
await authenticateWithTransport({
|
||||||
client,
|
client,
|
||||||
membership: { userId, deviceId, memberId: "" },
|
membership: { userId, deviceId, memberId: "" },
|
||||||
transport,
|
transport,
|
||||||
serverName: client.getDomain()!,
|
serverName,
|
||||||
roomId,
|
roomId,
|
||||||
slotId: "org.example.fake-slot#room",
|
slotId: "org.example.fake-slot#room",
|
||||||
role: "publisher",
|
role: "publisher",
|
||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
setCustomLivekitUrlUpdateError(null);
|
setCustomTransportUpdateError(null);
|
||||||
setCustomTransport(transport);
|
setCustomTransport(transport);
|
||||||
} catch {
|
} catch {
|
||||||
setCustomLivekitUrlUpdateError(
|
setCustomTransportUpdateError(
|
||||||
"invalid transport (did not update)",
|
"invalid transport (did not update)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[customTransportTextBuffer, setCustomTransport, client, roomId],
|
[customTransportTextBuffer, setCustomTransport, client, roomId],
|
||||||
)}
|
)}
|
||||||
value={customTransportTextBuffer ?? ""}
|
value={customTransportTextBuffer}
|
||||||
onChange={useCallback(
|
onChange={useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>): void => {
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
||||||
setCustomLivekitUrlTextBuffer(event.target.value);
|
setCustomTransportTextBuffer(event.target.value);
|
||||||
},
|
},
|
||||||
[setCustomLivekitUrlTextBuffer],
|
[setCustomTransportTextBuffer],
|
||||||
)}
|
)}
|
||||||
onCancel={useCallback(
|
onCancel={useCallback(
|
||||||
(e: React.FormEvent<HTMLFormElement>) => {
|
(e: React.FormEvent<HTMLFormElement>) => {
|
||||||
@@ -659,6 +659,11 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** The text shown in the custom transport field for a given setting value. */
|
||||||
|
function transportText(transport: UnstableLivekitTransport | null): string {
|
||||||
|
return transport === null ? "" : JSON.stringify(transport);
|
||||||
|
}
|
||||||
|
|
||||||
const TransportBox: FC<TransportInfo> = ({ transport, local }) => {
|
const TransportBox: FC<TransportInfo> = ({ transport, local }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const resolved = useBehavior(transport.resolved$);
|
const resolved = useBehavior(transport.resolved$);
|
||||||
|
|||||||
Reference in New Issue
Block a user