diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index acecfc4f..c3d26c4d 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -144,6 +144,7 @@ "feedback_tab_title": "Feedback", "more_tab_title": "More", "opt_in_description": "<0><1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.", + "show_debug_view": "", "speaker_device_selection_label": "Speaker" }, "star_rating_input_label_one": "{{count}} stars", diff --git a/src/debug/DebugView.module.css b/src/debug/DebugView.module.css new file mode 100644 index 00000000..bb371d1d --- /dev/null +++ b/src/debug/DebugView.module.css @@ -0,0 +1,28 @@ +.container { + padding: 0.5em; + z-index: 2; + display: flex; +} +.dataContainer { + background-color: var(--cpd-color-bg-canvas-default); + border-radius: 10px; + overflow: auto; + width: 500px; +} +.hideButton { + background: none; + border: none; +} +.memberContainer { + background-color: var(--cpd-color-bg-subtle-secondary); + border-radius: 10px; + margin: 0.5em; + padding: 0.5em; +} + +.encryptionEventContainer { + background-color: var(--cpd-color-bg-subtle-secondary); + border-radius: 10px; + margin: 0.5em; + padding: 0.5em; +} diff --git a/src/debug/DebugView.tsx b/src/debug/DebugView.tsx new file mode 100644 index 00000000..16d40f11 --- /dev/null +++ b/src/debug/DebugView.tsx @@ -0,0 +1,102 @@ +/* +Copyright 2024 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 { FC, useState } from "react"; +import { Text } from "@vector-im/compound-web"; +import { MatrixClient, MatrixEvent } from "matrix-js-sdk"; +import { CallMembership } from "matrix-js-sdk/src/matrixrtc/CallMembership"; + +import styles from "./DebugView.module.css"; + +interface Props { + rtcSession: MatrixRTCSession; + client: MatrixClient; +} + +export const DebugView: FC = ({ rtcSession, client }) => { + const [isShown, setIsShown] = useState(true); + const room = rtcSession.room; + const events = room + .getLiveTimeline() + .getEvents() + .filter((ev) => ev.getType() === "io.element.call.encryption_keys") + .map((ev: MatrixEvent) => ); + const listItems = rtcSession.memberships.map((m) => ( + + )); + return ( +
+ {isShown && ( +
+ {listItems} +
    {events}
+
+ )} + +
+ ); +}; + +interface MemberContainerProps { + membership: CallMembership; +} +const MemberContainer: FC = ({ membership }) => { + return ( +
+ + {membership.sender} + +
+ + Device Id: {membership.deviceId} + +
+ ); +}; + +interface EncryptionEventContainerProps { + event: MatrixEvent; +} +const EncryptionEventContainer: FC = ({ + event, +}) => { + const keys = event + .getContent() + .keys.map((obj: { index: number; key: string }) => ( + <> + index {obj.index}: {obj.key} +
+ + )); + return ( +
+ + {event.sender} + +
+ + Keys: {keys} + +
+
+ ); +}; diff --git a/src/livekit/MediaDevicesContext.tsx b/src/livekit/MediaDevicesContext.tsx index 2f654946..ae548cad 100644 --- a/src/livekit/MediaDevicesContext.tsx +++ b/src/livekit/MediaDevicesContext.tsx @@ -143,7 +143,7 @@ export const MediaDevicesProvider: FC = ({ children }) => { // On FF we dont need to query the names // (call enumerateDevices + create meadia stream to trigger permissions) - // for ouput devices because the selector wont be shown on FF. + // for output devices because the selector wont be shown on FF. const useOutputNames = usingNames && !isFirefox(); const [storedAudioInput, setStoredAudioInput] = useSetting(audioInputSetting); @@ -166,8 +166,8 @@ export const MediaDevicesProvider: FC = ({ children }) => { }, [setStoredAudioInput, audioInput.selectedId]); useEffect(() => { - // Skip setting state for ff output. Redundent since it is set to always return 'undefined' - // but makes it clear while debugging that this is not happening on FF. + perf ;) + // Skip setting state for ff output. Redundant since it is set to always return 'undefined' + // but makes it clear while debugging that this is not happening on FF. (+ perf) if (audioOutput.selectedId !== undefined && !isFirefox()) setStoredAudioOutput(audioOutput.selectedId); }, [setStoredAudioOutput, audioOutput.selectedId]); diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index 988dc0f8..faf7bc9f 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -235,7 +235,7 @@ export function useLiveKit( } catch (e) { if ((e as DOMException).name === "NotAllowedError") { logger.error( - "Fatal errror while syncing mute state: resetting", + "Fatal error while syncing mute state: resetting", e, ); if (type === MuteDevice.Microphone) { diff --git a/src/room/InCallView.module.css b/src/room/InCallView.module.css index cfc436c9..6891f621 100644 --- a/src/room/InCallView.module.css +++ b/src/room/InCallView.module.css @@ -23,6 +23,38 @@ limitations under the License. overflow-y: auto; } +.debugViewContainer { + display: flex; + flex-direction: row; + height: 100%; + width: 100%; +} + +.controlsOverlay { + position: relative; + flex: 1; + display: flex; + flex-direction: column; + overflow: auto; + overflow-inline: hidden; + /* There used to be a contain: strict here, but due to some bugs in Firefox, + this was causing the Z-ordering of modals to glitch out. It can be added back + if those issues appear to be resolved. */ +} + +.centerMessage { + display: flex; + flex: 1; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.centerMessage p { + display: block; + margin-bottom: 0; +} + .header { position: sticky; flex-shrink: 0; diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 22b6be8c..f96bd9ba 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -87,6 +87,11 @@ import { makeOneOnOneLayout } from "../grid/OneOnOneLayout"; import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout"; import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout"; import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout"; +import { DebugView } from "../debug/DebugView"; +import { + useSetting, + showDebugView as showDebugViewSetting, +} from "../settings/settings"; const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); @@ -558,54 +563,62 @@ export const InCallView: FC = ({ ); } + const [showDebugView] = useSetting(showDebugViewSetting); + return ( -
- {showHeader && - (hideHeader ? ( - // Cosmetic header to fill out space while still affecting the bounds - // of the grid -
- ) : ( -
- - - - - {!reducedControls && showControls && onShareClick !== null && ( - - )} - -
- ))} - - {renderContent()} - {footer} - {!noControls && } - +
+ {showDebugView && } + +
+ {showHeader && + (hideHeader ? ( + // Cosmetic header to fill out space while still affecting the bounds + // of the grid +
+ ) : ( +
+ + + + + {!reducedControls && showControls && onShareClick !== null && ( + + )} + +
+ ))} + + {renderContent()} + {footer} + {!noControls && ( + + )} + {" "} +
); }; diff --git a/src/settings/SettingsModal.tsx b/src/settings/SettingsModal.tsx index 6763cc5d..7d79f17c 100644 --- a/src/settings/SettingsModal.tsx +++ b/src/settings/SettingsModal.tsx @@ -45,6 +45,7 @@ import { optInAnalytics as optInAnalyticsSetting, developerSettingsTab as developerSettingsTabSetting, duplicateTiles as duplicateTilesSetting, + showDebugView as showDebugViewSetting, } from "./settings"; import { isFirefox } from "../Platform"; @@ -83,6 +84,8 @@ export const SettingsModal: FC = ({ ); const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting); + const [showDebugView, setShowDebugView] = useSetting(showDebugViewSetting); + // Generate a `SelectInput` with a list of devices for a given device kind. const generateDeviceSelection = ( devices: MediaDevice, @@ -275,6 +278,20 @@ export const SettingsModal: FC = ({ )} /> + + ): void => { + setShowDebugView(event.target.checked); + }, + [setShowDebugView], + )} + /> + ); diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 9c181ccf..2cd6eda4 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -78,6 +78,8 @@ export const developerSettingsTab = new Setting( export const duplicateTiles = new Setting("duplicate-tiles", 0); +export const showDebugView = new Setting("show-debug-view", false); + export const audioInput = new Setting( "audio-input", undefined,