More hacking on rtcsession
This commit is contained in:
23
src/livekit/LivekitFocus.ts
Normal file
23
src/livekit/LivekitFocus.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 New Vector Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Focus } from "matrix-js-sdk/src/matrixrtc/focus";
|
||||||
|
|
||||||
|
export interface LivekitFocus extends Focus {
|
||||||
|
type: "livekit";
|
||||||
|
livekit_service_url: string;
|
||||||
|
livekit_alias: string;
|
||||||
|
}
|
||||||
@@ -14,10 +14,13 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GroupCall, IOpenIDToken, MatrixClient } from "matrix-js-sdk";
|
import { IOpenIDToken, MatrixClient } from "matrix-js-sdk";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { Config } from "../config/Config";
|
import { LivekitFocus } from "./LivekitFocus";
|
||||||
|
import { useActiveFocus } from "../room/useActiveFocus";
|
||||||
|
|
||||||
export interface SFUConfig {
|
export interface SFUConfig {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -30,66 +33,52 @@ export type OpenIDClientParts = Pick<
|
|||||||
"getOpenIdToken" | "getDeviceId"
|
"getOpenIdToken" | "getDeviceId"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export function useOpenIDSFU(
|
||||||
|
client: OpenIDClientParts,
|
||||||
|
rtcSession: MatrixRTCSession
|
||||||
|
) {
|
||||||
|
const [sfuConfig, setSFUConfig] = useState<SFUConfig | undefined>(undefined);
|
||||||
|
|
||||||
|
const activeFocus = useActiveFocus(rtcSession);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const sfuConfig = activeFocus
|
||||||
|
? await getSFUConfigWithOpenID(client, activeFocus)
|
||||||
|
: undefined;
|
||||||
|
setSFUConfig(sfuConfig);
|
||||||
|
})();
|
||||||
|
}, [client, activeFocus]);
|
||||||
|
|
||||||
|
return sfuConfig;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getSFUConfigWithOpenID(
|
export async function getSFUConfigWithOpenID(
|
||||||
client: OpenIDClientParts,
|
client: OpenIDClientParts,
|
||||||
groupCall: GroupCall,
|
activeFocus: LivekitFocus
|
||||||
roomName: string
|
): Promise<SFUConfig | undefined> {
|
||||||
): Promise<SFUConfig> {
|
|
||||||
const openIdToken = await client.getOpenIdToken();
|
const openIdToken = await client.getOpenIdToken();
|
||||||
logger.debug("Got openID token", openIdToken);
|
logger.debug("Got openID token", openIdToken);
|
||||||
|
|
||||||
// if the call has a livekit service URL, try it.
|
|
||||||
if (groupCall.livekitServiceURL) {
|
|
||||||
try {
|
|
||||||
logger.info(
|
|
||||||
`Trying to get JWT from call's configured URL of ${groupCall.livekitServiceURL}...`
|
|
||||||
);
|
|
||||||
const sfuConfig = await getLiveKitJWT(
|
|
||||||
client,
|
|
||||||
groupCall.livekitServiceURL,
|
|
||||||
roomName,
|
|
||||||
openIdToken
|
|
||||||
);
|
|
||||||
logger.info(`Got JWT from call state event URL.`);
|
|
||||||
|
|
||||||
return sfuConfig;
|
|
||||||
} catch (e) {
|
|
||||||
logger.warn(
|
|
||||||
`Failed to get JWT from group call's configured URL of ${groupCall.livekitServiceURL}.`,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, try our configured one and, if it works, update the call's service URL in the state event
|
|
||||||
// NB. This wuill update it for everyone so we may end up with multiple clients updating this when they
|
|
||||||
// join at similar times, but we don't have a huge number of options here.
|
|
||||||
const urlFromConf = Config.get().livekit!.livekit_service_url;
|
|
||||||
logger.info(`Trying livekit service URL from our config: ${urlFromConf}...`);
|
|
||||||
try {
|
try {
|
||||||
|
logger.info(
|
||||||
|
`Trying to get JWT from call's active focus URL of ${activeFocus.livekit_service_url}...`
|
||||||
|
);
|
||||||
const sfuConfig = await getLiveKitJWT(
|
const sfuConfig = await getLiveKitJWT(
|
||||||
client,
|
client,
|
||||||
urlFromConf,
|
activeFocus.livekit_service_url,
|
||||||
roomName,
|
activeFocus.livekit_alias,
|
||||||
openIdToken
|
openIdToken
|
||||||
);
|
);
|
||||||
|
logger.info(`Got JWT from call's active focus URL.`);
|
||||||
logger.info(
|
|
||||||
`Got JWT, updating call livekit service URL with: ${urlFromConf}...`
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await groupCall.updateLivekitServiceURL(urlFromConf);
|
|
||||||
logger.info(`Call livekit service URL updated.`);
|
|
||||||
} catch (e) {
|
|
||||||
logger.warn(
|
|
||||||
`Failed to update call livekit service URL: continuing anyway.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sfuConfig;
|
return sfuConfig;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("Failed to get JWT from URL defined in Config.", e);
|
logger.warn(
|
||||||
throw e;
|
`Failed to get JWT from RTC session's active focus URL of ${activeFocus.livekit_service_url}.`,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { Room } from "livekit-client";
|
import { Room } from "livekit-client";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
import { Focus } from "matrix-js-sdk/src/matrixrtc/focus";
|
|
||||||
|
|
||||||
import type { IWidgetApiRequest } from "matrix-widget-api";
|
import type { IWidgetApiRequest } from "matrix-widget-api";
|
||||||
import { widget, ElementWidgetActions, JoinCallData } from "../widget";
|
import { widget, ElementWidgetActions, JoinCallData } from "../widget";
|
||||||
@@ -32,11 +31,9 @@ import { CallEndedView } from "./CallEndedView";
|
|||||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||||
import { useProfile } from "../profile/useProfile";
|
import { useProfile } from "../profile/useProfile";
|
||||||
import { findDeviceByName } from "../media-utils";
|
import { findDeviceByName } from "../media-utils";
|
||||||
//import { OpenIDLoader } from "../livekit/OpenIDLoader";
|
|
||||||
import { ActiveCall } from "./InCallView";
|
import { ActiveCall } from "./InCallView";
|
||||||
import { MuteStates, useMuteStates } from "./MuteStates";
|
import { MuteStates, useMuteStates } from "./MuteStates";
|
||||||
import { useMediaDevices, MediaDevices } from "../livekit/MediaDevicesContext";
|
import { useMediaDevices, MediaDevices } from "../livekit/MediaDevicesContext";
|
||||||
import { LivekitFocus } from "../livekit/LivekitFocus";
|
|
||||||
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
||||||
import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers";
|
import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers";
|
||||||
import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState";
|
import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState";
|
||||||
@@ -69,21 +66,11 @@ export function GroupCallView({
|
|||||||
hideHeader,
|
hideHeader,
|
||||||
rtcSession,
|
rtcSession,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
/*const {
|
|
||||||
state,
|
|
||||||
error,
|
|
||||||
enter,
|
|
||||||
leave,
|
|
||||||
participants,
|
|
||||||
unencryptedEventsFromUsers,
|
|
||||||
otelGroupCallMembership,
|
|
||||||
} = useGroupCall(groupCall, client);*/
|
|
||||||
|
|
||||||
const memberships = useMatrixRTCSessionMemberships(rtcSession);
|
const memberships = useMatrixRTCSessionMemberships(rtcSession);
|
||||||
const isJoined = useMatrixRTCSessionJoinState(rtcSession);
|
const isJoined = useMatrixRTCSessionJoinState(rtcSession);
|
||||||
|
|
||||||
const e2eeSharedKey = useManageRoomSharedKey(groupCall.room.roomId);
|
const e2eeSharedKey = useManageRoomSharedKey(rtcSession.room.roomId);
|
||||||
const isRoomE2EE = useIsRoomE2EE(groupCall.room.roomId);
|
const isRoomE2EE = useIsRoomE2EE(rtcSession.room.roomId);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -260,22 +247,9 @@ export function GroupCallView({
|
|||||||
const onReconnect = useCallback(() => {
|
const onReconnect = useCallback(() => {
|
||||||
setLeft(false);
|
setLeft(false);
|
||||||
setLeaveError(undefined);
|
setLeaveError(undefined);
|
||||||
rtcSession.joinRoomSession();
|
enterRTCSession(rtcSession);
|
||||||
}, [rtcSession]);
|
}, [rtcSession]);
|
||||||
|
|
||||||
const focus: Focus | undefined = rtcSession
|
|
||||||
.getOldestMembership()
|
|
||||||
?.getActiveFoci()?.[0];
|
|
||||||
if (
|
|
||||||
!focus ||
|
|
||||||
focus.type !== "livekit" ||
|
|
||||||
!(focus as LivekitFocus).livekit_alias ||
|
|
||||||
!(focus as LivekitFocus).livekit_service_url
|
|
||||||
) {
|
|
||||||
logger.error("Incompatible focus on call", focus);
|
|
||||||
return <ErrorView error={new Error("Call focus is not compatible!")} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e2eeEnabled && isRoomE2EE && !e2eeSharedKey) {
|
if (e2eeEnabled && isRoomE2EE && !e2eeSharedKey) {
|
||||||
return (
|
return (
|
||||||
<ErrorView
|
<ErrorView
|
||||||
@@ -294,11 +268,6 @@ export function GroupCallView({
|
|||||||
|
|
||||||
if (isJoined) {
|
if (isJoined) {
|
||||||
return (
|
return (
|
||||||
/*<OpenIDLoader
|
|
||||||
client={client}
|
|
||||||
groupCall={groupCall}
|
|
||||||
roomName={`${groupCall.room.roomId}-${groupCall.groupCallId}`}
|
|
||||||
>*/
|
|
||||||
<ActiveCall
|
<ActiveCall
|
||||||
client={client}
|
client={client}
|
||||||
rtcSession={rtcSession}
|
rtcSession={rtcSession}
|
||||||
@@ -309,7 +278,6 @@ export function GroupCallView({
|
|||||||
e2eeConfig={e2eeConfig}
|
e2eeConfig={e2eeConfig}
|
||||||
//otelGroupCallMembership={otelGroupCallMembership}
|
//otelGroupCallMembership={otelGroupCallMembership}
|
||||||
/>
|
/>
|
||||||
//</OpenIDLoader>
|
|
||||||
);
|
);
|
||||||
} else if (left) {
|
} else if (left) {
|
||||||
// The call ended view is shown for two reasons: prompting guests to create
|
// The call ended view is shown for two reasons: prompting guests to create
|
||||||
@@ -351,7 +319,7 @@ export function GroupCallView({
|
|||||||
<LobbyView
|
<LobbyView
|
||||||
matrixInfo={matrixInfo}
|
matrixInfo={matrixInfo}
|
||||||
muteStates={muteStates}
|
muteStates={muteStates}
|
||||||
onEnter={() => enter()}
|
onEnter={() => enterRTCSession(rtcSession)}
|
||||||
isEmbedded={isEmbedded}
|
isEmbedded={isEmbedded}
|
||||||
hideHeader={hideHeader}
|
hideHeader={hideHeader}
|
||||||
/>
|
/>
|
||||||
|
|||||||
68
src/room/useActiveFocus.ts
Normal file
68
src/room/useActiveFocus.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 New Vector Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
MatrixRTCSession,
|
||||||
|
MatrixRTCSessionEvent,
|
||||||
|
} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { deepCompare } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
|
import { LivekitFocus } from "../livekit/LivekitFocus";
|
||||||
|
|
||||||
|
function getActiveFocus(
|
||||||
|
rtcSession: MatrixRTCSession
|
||||||
|
): LivekitFocus | undefined {
|
||||||
|
const oldestMembership = rtcSession.getOldestMembership();
|
||||||
|
return oldestMembership?.getActiveFoci()[0] as LivekitFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currently active (livekit) focus for a MatrixRTC session
|
||||||
|
* This logic is specific to livekit foci where the whole call must use one
|
||||||
|
* and the same focus.
|
||||||
|
*/
|
||||||
|
export function useActiveFocus(
|
||||||
|
rtcSession: MatrixRTCSession
|
||||||
|
): LivekitFocus | undefined {
|
||||||
|
const [activeFocus, setActiveFocus] = useState(() =>
|
||||||
|
getActiveFocus(rtcSession)
|
||||||
|
);
|
||||||
|
|
||||||
|
const onMembershipsChanged = useCallback(() => {
|
||||||
|
const newActiveFocus = getActiveFocus(rtcSession);
|
||||||
|
|
||||||
|
if (!deepCompare(activeFocus, newActiveFocus)) {
|
||||||
|
setActiveFocus(newActiveFocus);
|
||||||
|
}
|
||||||
|
}, [activeFocus, rtcSession]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
rtcSession.on(
|
||||||
|
MatrixRTCSessionEvent.MembershipsChanged,
|
||||||
|
onMembershipsChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
rtcSession.off(
|
||||||
|
MatrixRTCSessionEvent.MembershipsChanged,
|
||||||
|
onMembershipsChanged
|
||||||
|
);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return activeFocus;
|
||||||
|
}
|
||||||
53
src/rtcSessionHelpers.ts
Normal file
53
src/rtcSessionHelpers.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 New Vector Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
|
|
||||||
|
import { PosthogAnalytics } from "./analytics/PosthogAnalytics";
|
||||||
|
import { LivekitFocus } from "./livekit/LivekitFocus";
|
||||||
|
import { Config } from "./config/Config";
|
||||||
|
|
||||||
|
function makeFocus(livekitAlias: string): LivekitFocus {
|
||||||
|
const urlFromConf = Config.get().livekit!.livekit_service_url;
|
||||||
|
if (!urlFromConf) {
|
||||||
|
throw new Error("No livekit_service_url is configured!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "livekit",
|
||||||
|
livekit_service_url: urlFromConf,
|
||||||
|
livekit_alias: livekitAlias,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enterRTCSession(rtcSession: MatrixRTCSession) {
|
||||||
|
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||||
|
PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId);
|
||||||
|
|
||||||
|
// This must be called before we start trying to join the call, as we need to
|
||||||
|
// have started tracking by the time calls start getting created.
|
||||||
|
//groupCallOTelMembership?.onJoinCall();
|
||||||
|
|
||||||
|
// right now we asume everything is a room-scoped call
|
||||||
|
const livekitAlias = rtcSession.room.roomId;
|
||||||
|
|
||||||
|
rtcSession.joinRoomSession([makeFocus(livekitAlias)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function leaveRTCSession(rtcSession: MatrixRTCSession) {
|
||||||
|
//groupCallOTelMembership?.onLeaveCall();
|
||||||
|
rtcSession.leaveRoomSession();
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import {
|
import {
|
||||||
MatrixRTCSession,
|
MatrixRTCSession,
|
||||||
MatrixRTCSessionEvent,
|
MatrixRTCSessionEvent,
|
||||||
@@ -26,6 +27,11 @@ export function useMatrixRTCSessionJoinState(
|
|||||||
const [isJoined, setJoined] = useState(rtcSession.isJoined());
|
const [isJoined, setJoined] = useState(rtcSession.isJoined());
|
||||||
|
|
||||||
const onJoinStateChanged = useCallback(() => {
|
const onJoinStateChanged = useCallback(() => {
|
||||||
|
logger.info(
|
||||||
|
`Session in room ${rtcSession.room.roomId} changed to ${
|
||||||
|
rtcSession.isJoined() ? "joined" : "left"
|
||||||
|
}`
|
||||||
|
);
|
||||||
setJoined(rtcSession.isJoined());
|
setJoined(rtcSession.isJoined());
|
||||||
}, [rtcSession]);
|
}, [rtcSession]);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { CallMembership } from "matrix-js-sdk/src/matrixrtc/CallMembership";
|
import { CallMembership } from "matrix-js-sdk/src/matrixrtc/CallMembership";
|
||||||
import {
|
import {
|
||||||
MatrixRTCSession,
|
MatrixRTCSession,
|
||||||
@@ -27,6 +28,9 @@ export function useMatrixRTCSessionMemberships(
|
|||||||
const [memberships, setMemberships] = useState(rtcSession.memberships);
|
const [memberships, setMemberships] = useState(rtcSession.memberships);
|
||||||
|
|
||||||
const onMembershipsChanged = useCallback(() => {
|
const onMembershipsChanged = useCallback(() => {
|
||||||
|
logger.info(
|
||||||
|
`Memberships changed for call in room ${rtcSession.room.roomId} (${rtcSession.memberships.length} members)`
|
||||||
|
);
|
||||||
setMemberships(rtcSession.memberships);
|
setMemberships(rtcSession.memberships);
|
||||||
}, [rtcSession]);
|
}, [rtcSession]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user