diff --git a/package.json b/package.json
index 63bbf0f1..b760eb5b 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"re-resizable": "^6.9.0",
"react": "^17.0.0",
"react-dom": "^17.0.0",
+ "react-json-view": "^1.21.3",
"react-router-dom": "^5.2.0"
},
"devDependencies": {
diff --git a/src/GroupCallInspector.jsx b/src/GroupCallInspector.jsx
new file mode 100644
index 00000000..cf35aad1
--- /dev/null
+++ b/src/GroupCallInspector.jsx
@@ -0,0 +1,143 @@
+import React, { useEffect, useState, useMemo } from "react";
+import { useCallback } from "react";
+import ReactJson from "react-json-view";
+
+function getCallUserId(call) {
+ return call.getOpponentMember()?.userId || call.invitee || null;
+}
+
+function getCallState(call) {
+ return {
+ opponentMemberId: getCallUserId(call),
+ state: call.state,
+ direction: call.direction,
+ };
+}
+
+function getHangupCallState(call) {
+ return {
+ ...getCallState(call),
+ hangupReason: call.hangupReason,
+ };
+}
+
+export function GroupCallInspector({ client, groupCall, show }) {
+ const [roomStateEvents, setRoomStateEvents] = useState([]);
+ const [toDeviceEvents, setToDeviceEvents] = useState([]);
+ const [state, setState] = useState({
+ userId: client.getUserId(),
+ });
+
+ const updateState = useCallback(
+ (next) => setState((prev) => ({ ...prev, ...next })),
+ []
+ );
+
+ useEffect(() => {
+ function onUpdateRoomState(event) {
+ if (event) {
+ setRoomStateEvents((prev) => [
+ ...prev,
+ {
+ eventType: event.getType(),
+ stateKey: event.getStateKey(),
+ content: event.getContent(),
+ },
+ ]);
+ }
+
+ const roomEvent = groupCall.room.currentState
+ .getStateEvents("org.matrix.msc3401.call", groupCall.groupCallId)
+ .getContent();
+
+ const memberEvents = Object.fromEntries(
+ groupCall.room.currentState
+ .getStateEvents("org.matrix.msc3401.call.member")
+ .map((event) => [event.getStateKey(), event.getContent()])
+ );
+
+ updateState({
+ ["org.matrix.msc3401.call"]: roomEvent,
+ ["org.matrix.msc3401.call.member"]: memberEvents,
+ });
+ }
+
+ function onCallsChanged() {
+ const calls = groupCall.calls.map(getCallState);
+
+ updateState({ calls });
+ }
+
+ function onCallHangup(call) {
+ setState(({ hangupCalls, ...rest }) => ({
+ ...rest,
+ hangupCalls: hangupCalls
+ ? [...hangupCalls, getHangupCallState(call)]
+ : [getHangupCallState(call)],
+ }));
+ }
+
+ function onToDeviceEvent(event) {
+ const eventType = event.getType();
+
+ if (
+ !(
+ eventType.startsWith("m.call.") ||
+ eventType.startsWith("org.matrix.call.")
+ )
+ ) {
+ return;
+ }
+
+ const content = event.getContent();
+
+ if (content.conf_id && content.conf_id !== groupCall.groupCallId) {
+ return;
+ }
+
+ setToDeviceEvents((prev) => [...prev, { eventType, content }]);
+ }
+
+ client.on("RoomState.events", onUpdateRoomState);
+ groupCall.on("calls_changed", onCallsChanged);
+ client.on("state", onCallsChanged);
+ client.on("hangup", onCallHangup);
+ client.on("toDeviceEvent", onToDeviceEvent);
+
+ onUpdateRoomState();
+ }, [client, groupCall]);
+
+ const toDeviceEventsByCall = useMemo(() => {
+ const result = {};
+
+ for (const event of toDeviceEvents) {
+ const callId = event.content.call_id;
+ result[callId] = result[callId] || [];
+ result[callId].push(event);
+ }
+
+ return result;
+ }, [toDeviceEvents]);
+
+ return (
+
+ {show && (
+
+ )}
+
+ );
+}
diff --git a/src/Room.jsx b/src/Room.jsx
index dc663894..f75a96f4 100644
--- a/src/Room.jsx
+++ b/src/Room.jsx
@@ -24,6 +24,7 @@ import {
LayoutToggleButton,
ScreenshareButton,
DropdownButton,
+ SettingsButton,
} from "./RoomButton";
import { Header, LeftNav, RightNav, CenterNav } from "./Header";
import { Button } from "./Input";
@@ -37,6 +38,7 @@ import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed";
import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream";
import { fetchGroupCall } from "./ConferenceCallManagerHooks";
import { ErrorModal } from "./ErrorModal";
+import { GroupCallInspector } from "./GroupCallInspector";
function useLoadGroupCall(client, roomId) {
const [state, setState] = useState({
@@ -109,6 +111,7 @@ export function GroupCallView({ client, groupCall }) {
} else if (state === GroupCallState.Entered) {
return (
{roomName}
+ setShowInspector((prev) => !prev)}
+ />
+
>
);
}
diff --git a/yarn.lock b/yarn.lock
index 2c300675..2da842e2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -169,7 +169,7 @@
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz"
integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.15.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
@@ -625,6 +625,11 @@ base-x@^3.0.2:
dependencies:
safe-buffer "^5.0.1"
+base16@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
+ integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=
+
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -917,6 +922,13 @@ crc-32@^0.3.0:
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-0.3.0.tgz#6a3d3687f5baec41f7e9b99fe1953a2e5d19775e"
integrity sha1-aj02h/W67EH36bmf4ZU6Ll0Zd14=
+cross-fetch@^3.0.4:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
+ integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==
+ dependencies:
+ node-fetch "2.6.1"
+
css-blank-pseudo@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5"
@@ -1307,6 +1319,18 @@ fbemitter@^2.0.0:
dependencies:
fbjs "^0.8.4"
+fbemitter@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3"
+ integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==
+ dependencies:
+ fbjs "^3.0.0"
+
+fbjs-css-vars@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
+ integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
+
fbjs@0.1.0-alpha.7:
version "0.1.0-alpha.7"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.1.0-alpha.7.tgz#ad4308b8f232fb3c73603349ea725d1e9c39323c"
@@ -1329,6 +1353,19 @@ fbjs@^0.8.4:
setimmediate "^1.0.5"
ua-parser-js "^0.7.18"
+fbjs@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165"
+ integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==
+ dependencies:
+ cross-fetch "^3.0.4"
+ fbjs-css-vars "^1.0.0"
+ loose-envify "^1.0.0"
+ object-assign "^4.1.0"
+ promise "^7.1.1"
+ setimmediate "^1.0.5"
+ ua-parser-js "^0.7.18"
+
fflate@^0.4.1:
version "0.4.8"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
@@ -1372,6 +1409,14 @@ flux@2.1.1:
fbjs "0.1.0-alpha.7"
immutable "^3.7.4"
+flux@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.2.tgz#d71dcaf6cb51ca059f303f3d964d6f325d444952"
+ integrity sha512-u/ucO5ezm3nBvdaSGkWpDlzCePoV+a9x3KHmy13TV/5MzOaCZDN8Mfd94jmf0nOi8ZZay+nOKbBUkOe2VNaupQ==
+ dependencies:
+ fbemitter "^3.0.0"
+ fbjs "^3.0.0"
+
focus-lock@^0.9.1:
version "0.9.2"
resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.9.2.tgz#9d30918aaa99b1b97677731053d017f82a540d5b"
@@ -1749,6 +1794,16 @@ lodash-move@^1.1.1:
dependencies:
lodash "^4.6.1"
+lodash.curry@^4.0.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
+ integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA=
+
+lodash.flow@^3.3.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
+ integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
+
lodash@^4.17.20, lodash@^4.6.1:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
@@ -1905,6 +1960,11 @@ nanoid@^3.1.25:
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.28.tgz"
integrity sha512-gSu9VZ2HtmoKYe/lmyPFES5nknFrHa+/DT9muUFWFMi6Jh9E1I7bkvlQ8xxf1Kos9pi9o8lBnIOkatMhKX/YUw==
+node-fetch@2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
+ integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
+
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
@@ -2442,6 +2502,11 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+pure-color@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
+ integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
+
qrcode@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83"
@@ -2484,6 +2549,16 @@ re-resizable@^6.9.0:
dependencies:
fast-memoize "^2.5.1"
+react-base16-styling@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
+ integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=
+ dependencies:
+ base16 "^1.0.0"
+ lodash.curry "^4.0.1"
+ lodash.flow "^3.3.0"
+ pure-color "^1.2.0"
+
react-beautiful-dnd@^13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz#ec97c81093593526454b0de69852ae433783844d"
@@ -2535,6 +2610,21 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+react-json-view@^1.21.3:
+ version "1.21.3"
+ resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475"
+ integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==
+ dependencies:
+ flux "^4.0.1"
+ react-base16-styling "^0.6.0"
+ react-lifecycles-compat "^3.0.4"
+ react-textarea-autosize "^8.3.2"
+
+react-lifecycles-compat@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+ integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
react-redux@^7.2.0:
version "7.2.5"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.5.tgz#213c1b05aa1187d9c940ddfc0b29450957f6a3b8"
@@ -2576,6 +2666,15 @@ react-router@5.2.1:
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
+react-textarea-autosize@^8.3.2:
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8"
+ integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==
+ dependencies:
+ "@babel/runtime" "^7.10.2"
+ use-composed-ref "^1.0.0"
+ use-latest "^1.0.0"
+
react-transition-group@^4.4.1:
version "4.4.2"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
@@ -2871,6 +2970,11 @@ tough-cookie@~2.5.0:
psl "^1.1.28"
punycode "^2.1.1"
+ts-essentials@^2.0.3:
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745"
+ integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==
+
tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@@ -2928,6 +3032,25 @@ use-callback-ref@^1.2.5:
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5"
integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==
+use-composed-ref@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.1.0.tgz#9220e4e94a97b7b02d7d27eaeab0b37034438bbc"
+ integrity sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==
+ dependencies:
+ ts-essentials "^2.0.3"
+
+use-isomorphic-layout-effect@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225"
+ integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==
+
+use-latest@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232"
+ integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==
+ dependencies:
+ use-isomorphic-layout-effect "^1.0.0"
+
use-memo-one@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.2.tgz#0c8203a329f76e040047a35a1197defe342fab20"