Merge remote-tracking branch 'origin/livekit' into dbkr/write_key_with_right_roomid

This commit is contained in:
David Baker
2023-10-11 12:53:54 +01:00
7 changed files with 98 additions and 41 deletions

View File

@@ -101,6 +101,17 @@ export function useLiveKit(
// block audio from being enabled until the connection is finished.
const [blockAudio, setBlockAudio] = useState(true);
// Store if audio/video are currently updating. If to prohibit unnecessary calls
// to setMicrophoneEnabled/setCameraEnabled
const audioMuteUpdating = useRef(false);
const videoMuteUpdating = useRef(false);
// Store the current button mute state that gets passed to this hook via props.
// We need to store it for awaited code that relies on the current value.
const buttonEnabled = useRef({
audio: initialMuteStates.current.audio.enabled,
video: initialMuteStates.current.video.enabled,
});
// We have to create the room manually here due to a bug inside
// @livekit/components-react. JSON.stringify() is used in deps of a
// useEffect() with an argument that references itself, if E2EE is enabled
@@ -137,20 +148,50 @@ export function useLiveKit(
// and setting tracks to be enabled during this time causes errors.
if (room !== undefined && connectionState === ConnectionState.Connected) {
const participant = room.localParticipant;
if (participant.isMicrophoneEnabled !== muteStates.audio.enabled) {
participant
.setMicrophoneEnabled(muteStates.audio.enabled)
.catch((e) =>
logger.error("Failed to sync audio mute state with LiveKit", e)
);
}
if (participant.isCameraEnabled !== muteStates.video.enabled) {
participant
.setCameraEnabled(muteStates.video.enabled)
.catch((e) =>
logger.error("Failed to sync video mute state with LiveKit", e)
);
}
// Always update the muteButtonState Ref so that we can read the current
// state in awaited blocks.
buttonEnabled.current = {
audio: muteStates.audio.enabled,
video: muteStates.video.enabled,
};
const syncMuteStateAudio = async () => {
if (
participant.isMicrophoneEnabled !== buttonEnabled.current.audio &&
!audioMuteUpdating.current
) {
audioMuteUpdating.current = true;
try {
await participant.setMicrophoneEnabled(buttonEnabled.current.audio);
} catch (e) {
logger.error("Failed to sync audio mute state with LiveKit", e);
}
audioMuteUpdating.current = false;
// Run the check again after the change is done. Because the user
// can update the state (presses mute button) while the device is enabling
// itself we need might need to update the mute state right away.
// This async recursion makes sure that setCamera/MicrophoneEnabled is
// called as little times as possible.
syncMuteStateAudio();
}
};
const syncMuteStateVideo = async () => {
if (
participant.isCameraEnabled !== buttonEnabled.current.video &&
!videoMuteUpdating.current
) {
videoMuteUpdating.current = true;
try {
await participant.setCameraEnabled(buttonEnabled.current.video);
} catch (e) {
logger.error("Failed to sync audio mute state with LiveKit", e);
}
videoMuteUpdating.current = false;
// see above
syncMuteStateVideo();
}
};
syncMuteStateAudio();
syncMuteStateVideo();
}
}, [room, muteStates, connectionState]);

View File

@@ -76,9 +76,18 @@ function waitForSync(client: MatrixClient) {
function secureRandomString(entropyBytes: number): string {
const key = new Uint8Array(entropyBytes);
crypto.getRandomValues(key);
// encode to base64url as this value goes into URLs
// base64url is just base64 with thw two non-alphanum characters swapped out for
// ones that can be put in a URL without encoding. Browser JS has a native impl
// for base64 encoding but only a string (there isn't one that takes a UInt8Array
// yet) so just use the built-in one and convert, replace the chars and strip the
// padding from the end (otherwise we'd need to pull in another dependency).
return btoa(
key.reduce((acc, current) => acc + String.fromCharCode(current), "")
).replace(/=*$/, "");
)
.replace("+", "-")
.replace("/", "_")
.replace(/=*$/, "");
}
/**
@@ -395,9 +404,16 @@ export function getRelativeRoomUrl(
roomName?: string,
password?: string
): string {
// The password shouldn't need URL encoding here (we generate URL-safe ones) but encode
// it in case it came from another client that generated a non url-safe one
const encodedPassword = password ? encodeURIComponent(password) : undefined;
if (password && encodedPassword !== password) {
logger.info("Encoded call password used non URL-safe chars: buggy client?");
}
return `/room/#${
roomName ? "/" + roomAliasLocalpartFromRoomName(roomName) : ""
}?roomId=${roomId}${password ? "&" + PASSWORD_STRING + password : ""}`;
}?roomId=${roomId}${password ? "&" + PASSWORD_STRING + encodedPassword : ""}`;
}
export function getAvatarUrl(

View File

@@ -110,7 +110,7 @@ export function GroupCallView({
// Count each member only once, regardless of how many devices they use
const participantCount = useMemo(
() => new Set<string>(memberships.map((m) => m.member.userId)).size,
() => new Set<string>(memberships.map((m) => m.sender!)).size,
[memberships]
);

View File

@@ -41,7 +41,7 @@ export function enterRTCSession(rtcSession: MatrixRTCSession) {
// have started tracking by the time calls start getting created.
//groupCallOTelMembership?.onJoinCall();
// right now we asume everything is a room-scoped call
// right now we assume everything is a room-scoped call
const livekitAlias = rtcSession.room.roomId;
rtcSession.joinRoomSession([makeFocus(livekitAlias)]);