diff --git a/.vscode/settings.json b/.vscode/settings.json index 5b43834a..fe488f68 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,21 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.insertSpaces": true, - "editor.tabSize": 2 + "editor.tabSize": 2, + "[typescriptreact]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + }, + "[javascriptreact]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + }, + "[typescript]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + }, + "[javascript]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + } } diff --git a/src/home/RegisteredView.jsx b/src/home/RegisteredView.jsx index 1d07d1c7..b5fef745 100644 --- a/src/home/RegisteredView.jsx +++ b/src/home/RegisteredView.jsx @@ -47,7 +47,7 @@ export function RegisteredView({ client }) { setError(undefined); setLoading(true); - const roomIdOrAlias = await createRoom(client, roomName, ptt); + const [roomIdOrAlias] = await createRoom(client, roomName, ptt); if (roomIdOrAlias) { history.push(`/room/${roomIdOrAlias}`); diff --git a/src/home/UnauthenticatedView.jsx b/src/home/UnauthenticatedView.jsx index f324d504..a6d7a6ed 100644 --- a/src/home/UnauthenticatedView.jsx +++ b/src/home/UnauthenticatedView.jsx @@ -70,7 +70,7 @@ export function UnauthenticatedView() { let roomIdOrAlias; try { - roomIdOrAlias = await createRoom(client, roomName, ptt); + [roomIdOrAlias] = await createRoom(client, roomName, ptt); } catch (error) { if (error.errcode === "M_ROOM_IN_USE") { setOnFinished(() => () => { diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index db76773c..90cd00ed 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -285,8 +285,8 @@ export function isLocalRoomId(roomId: string): boolean { export async function createRoom( client: MatrixClient, name: string -): Promise { - await client.createRoom({ +): Promise<[string, string]> { + const result = await client.createRoom({ visibility: Visibility.Private, preset: Preset.PublicChat, name, @@ -316,7 +316,7 @@ export async function createRoom( }, }); - return fullAliasFromRoomName(name, client); + return [fullAliasFromRoomName(name, client), result.room_id]; } export function getRoomUrl(roomId: string): string { diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index 0d7fb7c7..301ba54f 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -21,6 +21,7 @@ import { GroupCallIntent, } from "matrix-js-sdk/src/webrtc/groupCall"; import { GroupCallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/groupCallEventHandler"; +import { ClientEvent } from "matrix-js-sdk/src/client"; import type { MatrixClient } from "matrix-js-sdk/src/client"; import type { Room } from "matrix-js-sdk/src/models/room"; @@ -44,9 +45,38 @@ export const useLoadGroupCall = ( useEffect(() => { setState({ loading: true }); + const waitForRoom = async (roomId: string): Promise => { + const room = client.getRoom(roomId); + if (room) return room; + console.log(`Room ${roomId} hasn't arrived yet: waiting`); + + const waitPromise = new Promise((resolve) => { + const onRoomEvent = async (room: Room) => { + if (room.roomId === roomId) { + client.removeListener(ClientEvent.Room, onRoomEvent); + resolve(room); + } + }; + client.on(ClientEvent.Room, onRoomEvent); + }); + + // race the promise with a timeout so we don't + // wait forever for the room + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => { + reject(new Error("Timed out trying to join room")); + }, 30000); + }); + + return Promise.race([waitPromise, timeoutPromise]); + }; + const fetchOrCreateRoom = async (): Promise => { try { - return await client.joinRoom(roomIdOrAlias, { viaServers }); + const room = await client.joinRoom(roomIdOrAlias, { viaServers }); + // wait for the room to come down the sync stream, otherwise + // client.getRoom() won't return the room. + return waitForRoom(room.roomId); } catch (error) { if ( isLocalRoomId(roomIdOrAlias) && @@ -55,8 +85,12 @@ export const useLoadGroupCall = ( error.message.indexOf("Failed to fetch alias") !== -1)) ) { // The room doesn't exist, but we can create it - await createRoom(client, roomNameFromRoomId(roomIdOrAlias)); - return await client.joinRoom(roomIdOrAlias, { viaServers }); + const [, roomId] = await createRoom( + client, + roomNameFromRoomId(roomIdOrAlias) + ); + // likewise, wait for the room + return await waitForRoom(roomId); } else { throw error; } diff --git a/src/video-grid/useMediaStream.ts b/src/video-grid/useMediaStream.ts index 79e8292b..5fbf57d0 100644 --- a/src/video-grid/useMediaStream.ts +++ b/src/video-grid/useMediaStream.ts @@ -202,7 +202,12 @@ export const useSpatialMediaStream = ( const sourceRef = useRef(); useEffect(() => { - if (spatialAudio && tileRef.current && !mute) { + if ( + spatialAudio && + tileRef.current && + !mute && + stream.getAudioTracks().length > 0 + ) { if (!pannerNodeRef.current) { pannerNodeRef.current = new PannerNode(audioContext, { panningModel: "HRTF",