From 1bf1813a77f284b832c402818e279c89b6049f3e Mon Sep 17 00:00:00 2001 From: alariej Date: Fri, 17 Mar 2023 17:20:16 +0100 Subject: [PATCH 01/18] Fix for Android WebView, which does not support navigator.mediaSession --- src/room/useGroupCall.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/room/useGroupCall.ts b/src/room/useGroupCall.ts index 60f2d67..d6c785a 100644 --- a/src/room/useGroupCall.ts +++ b/src/room/useGroupCall.ts @@ -189,7 +189,7 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType { ]; for (const mediaAction of mediaActions) { - navigator.mediaSession.setActionHandler( + navigator.mediaSession?.setActionHandler( mediaAction, doNothingMediaActionCallback ); @@ -197,7 +197,7 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType { return () => { for (const mediaAction of mediaActions) { - navigator.mediaSession.setActionHandler(mediaAction, null); + navigator.mediaSession?.setActionHandler(mediaAction, null); } }; }, [doNothingMediaActionCallback]); From 698bea93e3eaefb788012d4ce4f51c062e1f4675 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 22 Mar 2023 11:33:50 -0400 Subject: [PATCH 02/18] Update matrix-widget-api --- package.json | 2 +- yarn.lock | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3b6368d..f7e2263 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "i18next-http-backend": "^1.4.4", "lodash": "^4.17.21", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8cbbdaa239e449848e8874f041ef1879c1956696", - "matrix-widget-api": "^1.0.0", + "matrix-widget-api": "^1.3.1", "mermaid": "^8.13.8", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/yarn.lock b/yarn.lock index 3b6c84f..cd1d7ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10387,6 +10387,14 @@ matrix-widget-api@^1.0.0: "@types/events" "^3.0.0" events "^3.2.0" +matrix-widget-api@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.3.1.tgz#e38f404c76bb15c113909505c1c1a5b4d781c2f5" + integrity sha512-+rN6vGvnXm+fn0uq9r2KWSL/aPtehD6ObC50jYmUcEfgo8CUpf9eUurmjbRlwZkWq3XHXFuKQBUCI9UzqWg37Q== + dependencies: + "@types/events" "^3.0.0" + events "^3.2.0" + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" From 76c02773017791fb7ca931f89d7150620a3628f5 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 22 Mar 2023 11:41:41 -0400 Subject: [PATCH 03/18] Update matrix-js-sdk --- package.json | 2 +- src/room/GroupCallInspector.tsx | 6 +++--- yarn.lock | 26 +++++++++----------------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index f7e2263..8a95ba7 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "i18next-browser-languagedetector": "^6.1.8", "i18next-http-backend": "^1.4.4", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8cbbdaa239e449848e8874f041ef1879c1956696", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#f795577e14d5e56b2f57d4b9a686d832c5210e3d", "matrix-widget-api": "^1.3.1", "mermaid": "^8.13.8", "normalize.css": "^8.0.1", diff --git a/src/room/GroupCallInspector.tsx b/src/room/GroupCallInspector.tsx index 648a0a1..399f8d7 100644 --- a/src/room/GroupCallInspector.tsx +++ b/src/room/GroupCallInspector.tsx @@ -31,7 +31,7 @@ import { MatrixEvent, IContent } from "matrix-js-sdk/src/models/event"; import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; -import { CallEvent } from "matrix-js-sdk/src/webrtc/call"; +import { CallEvent, VoipEvent } from "matrix-js-sdk/src/webrtc/call"; import styles from "./GroupCallInspector.module.css"; import { SelectInput } from "../input/SelectInput"; @@ -235,7 +235,7 @@ function reducer( action: { type?: CallEvent | ClientEvent | RoomStateEvent; event?: MatrixEvent; - rawEvent?: Record; + rawEvent?: VoipEvent; callStateEvent?: MatrixEvent; memberStateEvents?: MatrixEvent[]; } @@ -387,7 +387,7 @@ function useGroupCallState( dispatch({ type: ClientEvent.ReceivedVoipEvent, event }); } - function onSendVoipEvent(event: Record) { + function onSendVoipEvent(event: VoipEvent) { dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event }); } diff --git a/yarn.lock b/yarn.lock index cd1d7ef..1852bfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1821,10 +1821,10 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== -"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.3": - version "0.1.0-alpha.4" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.4.tgz#1b20294e0354c3dcc9c7dc810d883198a4042f04" - integrity sha512-mdaDKrw3P5ZVCpq0ioW0pV6ihviDEbS8ZH36kpt9stLKHwwDSopPogE6CkQhi0B1jn1yBUtOYi32mBV/zcOR7g== +"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.5": + version "0.1.0-alpha.5" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.5.tgz#60ede2c43b9d808ba8cf46085a3b347b290d9658" + integrity sha512-2KjAgWNGfuGLNjJwsrs6gGX157vmcTfNrA4u249utgnMPbJl7QwuUqh1bGxQ0PpK06yvZjgPlkna0lTbuwtuQw== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": version "3.2.14" @@ -10362,31 +10362,23 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#8cbbdaa239e449848e8874f041ef1879c1956696": - version "23.4.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/8cbbdaa239e449848e8874f041ef1879c1956696" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#f795577e14d5e56b2f57d4b9a686d832c5210e3d": + version "23.5.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/f795577e14d5e56b2f57d4b9a686d832c5210e3d" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.3" + "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.5" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4" loglevel "^1.7.1" matrix-events-sdk "0.0.1" - matrix-widget-api "^1.0.0" + matrix-widget-api "^1.3.1" p-retry "4" sdp-transform "^2.14.1" unhomoglyph "^1.0.6" uuid "9" -matrix-widget-api@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.1.1.tgz#d3fec45033d0cbc14387a38ba92dac4dbb1be962" - integrity sha512-gNSgmgSwvOsOcWK9k2+tOhEMYBiIMwX95vMZu0JqY7apkM02xrOzUBuPRProzN8CnbIALH7e3GAhatF6QCNvtA== - dependencies: - "@types/events" "^3.0.0" - events "^3.2.0" - matrix-widget-api@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.3.1.tgz#e38f404c76bb15c113909505c1c1a5b4d781c2f5" From 247d15cbb514eafc87e6d11da0381e61f897f715 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 28 Mar 2023 15:24:33 +0100 Subject: [PATCH 04/18] Update js-sdk for https://github.com/matrix-org/matrix-js-sdk/commit/da03c3b529576a8fcde6f2c9a171fa6cca012830 --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 8a95ba7..efa077d 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "i18next-browser-languagedetector": "^6.1.8", "i18next-http-backend": "^1.4.4", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#f795577e14d5e56b2f57d4b9a686d832c5210e3d", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#da03c3b529576a8fcde6f2c9a171fa6cca012830", "matrix-widget-api": "^1.3.1", "mermaid": "^8.13.8", "normalize.css": "^8.0.1", diff --git a/yarn.lock b/yarn.lock index 1852bfe..539ebf9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10362,9 +10362,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#f795577e14d5e56b2f57d4b9a686d832c5210e3d": - version "23.5.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/f795577e14d5e56b2f57d4b9a686d832c5210e3d" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#da03c3b529576a8fcde6f2c9a171fa6cca012830": + version "24.0.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/da03c3b529576a8fcde6f2c9a171fa6cca012830" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.5" From d53be695f906615b7a49893e1d102aa5199fa5ac Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 28 Mar 2023 15:33:11 +0100 Subject: [PATCH 05/18] Work around Vite unbounded memory usage Port fix from otel branch where it appears to be working --- .github/workflows/build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index eee1406..ba27e26 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -23,6 +23,9 @@ jobs: SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} SENTRY_URL: ${{ secrets.SENTRY_URL }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + # This appears to be necessary to stop Vite from OOMing + # https://github.com/vitejs/vite/issues/2433 + NODE_OPTIONS: "--max-old-space-size=16384" - name: Upload Artifact uses: actions/upload-artifact@v2 with: From 15e4c01c5d45d7506fd8ea86bbeae1c4de64e5d7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 28 Mar 2023 15:47:59 +0100 Subject: [PATCH 06/18] Add max old space fix to publish workflow too --- .github/workflows/publish.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index f49980d..3558797 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -40,6 +40,9 @@ jobs: SENTRY_URL: ${{ secrets.SENTRY_URL }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} VITE_APP_VERSION: ${{ github.event.release.tag_name }} + # This appears to be necessary to stop Vite from OOMing + # https://github.com/vitejs/vite/issues/2433 + NODE_OPTIONS: "--max-old-space-size=16384" - name: Create Tarball env: From 77c6357b08b2f71a890e000a091536312d4b0648 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 29 Mar 2023 12:28:04 +0100 Subject: [PATCH 07/18] Use js-sdk from hangup refactor branch https://github.com/matrix-org/matrix-js-sdk/pull/3234 --- package.json | 2 +- src/otel/OTelGroupCallMembership.ts | 86 ++++++++++++++++++++++++++--- src/otel/otel.ts | 4 +- src/room/GroupCallInspector.tsx | 23 ++++++-- src/room/useGroupCall.ts | 2 + yarn.lock | 20 +++++-- 6 files changed, 114 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index a32fd8c..4ecc42d 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "i18next-browser-languagedetector": "^6.1.8", "i18next-http-backend": "^1.4.4", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#23837266fca5ee799b51a722f7b8eefb2f5ac140", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#042f2ed76c501c10dde98a31732fd92d862e2187", "matrix-widget-api": "^1.0.0", "mermaid": "^8.13.8", "normalize.css": "^8.0.1", diff --git a/src/otel/OTelGroupCallMembership.ts b/src/otel/OTelGroupCallMembership.ts index 764249f..4c6d308 100644 --- a/src/otel/OTelGroupCallMembership.ts +++ b/src/otel/OTelGroupCallMembership.ts @@ -14,15 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -import opentelemetry, { Span, Attributes } from "@opentelemetry/api"; -import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions"; +import opentelemetry, { Span, Attributes, Context } from "@opentelemetry/api"; +import { logger } from "@sentry/utils"; import { GroupCall, MatrixClient, MatrixEvent, RoomMember, } from "matrix-js-sdk"; -import { VoipEvent } from "matrix-js-sdk/src/webrtc/call"; +import { + CallState, + MatrixCall, + VoipEvent, +} from "matrix-js-sdk/src/webrtc/call"; +import { + CallsByUserAndDevice, + GroupCallEvent, +} from "matrix-js-sdk/src/webrtc/groupCall"; import { ElementCallOpenTelemetry } from "./otel"; @@ -68,21 +76,37 @@ function flattenVoipEventRecursive( } } +interface CallTrackingInfo { + userId: string; + deviceId: string; + call: MatrixCall; + span: Span; +} + /** * Represent the span of time which we intend to be joined to a group call */ export class OTelGroupCallMembership { private callMembershipSpan?: Span; + private groupCallContext?: Context; private myUserId: string; + private myDeviceId: string; private myMember: RoomMember; + private callsByCallId = new Map(); constructor(private groupCall: GroupCall, client: MatrixClient) { this.myUserId = client.getUserId(); + this.myDeviceId = client.getDeviceId(); this.myMember = groupCall.room.getMember(client.getUserId()); - ElementCallOpenTelemetry.instance.provider.resource.attributes[ - SemanticResourceAttributes.SERVICE_NAME - ] = `element-call-${this.myUserId}-${client.getDeviceId()}`; + this.groupCall.on(GroupCallEvent.CallsChanged, this.onCallsChanged); + } + + dispose() { + this.groupCall.removeListener( + GroupCallEvent.CallsChanged, + this.onCallsChanged + ); } public onJoinCall() { @@ -96,12 +120,13 @@ export class OTelGroupCallMembership { this.groupCall.groupCallId ); this.callMembershipSpan.setAttribute("matrix.userId", this.myUserId); + this.callMembershipSpan.setAttribute("matrix.deviceId", this.myDeviceId); this.callMembershipSpan.setAttribute( "matrix.displayName", this.myMember.name ); - opentelemetry.trace.setSpan( + this.groupCallContext = opentelemetry.trace.setSpan( opentelemetry.context.active(), this.callMembershipSpan ); @@ -126,12 +151,55 @@ export class OTelGroupCallMembership { } this.callMembershipSpan?.addEvent( - `otel_onRoomStateEvent_${event.getType()}`, + `matrix.roomStateEvent_${event.getType()}`, flattenVoipEvent(event.getContent()) ); } - public onSendEvent(event: VoipEvent) { + public onCallsChanged = (calls: CallsByUserAndDevice) => { + for (const [userId, userCalls] of calls.entries()) { + for (const [deviceId, call] of userCalls.entries()) { + if (!this.callsByCallId.has(call.callId)) { + const span = ElementCallOpenTelemetry.instance.tracer.startSpan( + `matrix.call`, + undefined, + this.groupCallContext + ); + // XXX: anonymity + span.setAttribute("matrix.call.target.userId", userId); + span.setAttribute("matrix.call.target.deviceId", deviceId); + this.callsByCallId.set(call.callId, { + userId, + deviceId, + call, + span, + }); + } + } + } + + for (const callTrackingInfo of this.callsByCallId.values()) { + const userCalls = calls.get(callTrackingInfo.userId); + if (!userCalls || !userCalls.has(callTrackingInfo.deviceId)) { + callTrackingInfo.span.end(); + this.callsByCallId.delete(callTrackingInfo.call.callId); + } + } + }; + + public onCallStateChange(call: MatrixCall, newState: CallState) { + const callTrackingInfo = this.callsByCallId.get(call.callId); + if (!callTrackingInfo) { + logger.error(`Got call state change for unknown call ID ${call.callId}`); + return; + } + + callTrackingInfo.span.addEvent("matrix.call.stateChange", { + state: newState, + }); + } + + public onSendEvent(call: MatrixCall, event: VoipEvent) { const eventType = event.eventType as string; if (!eventType.startsWith("m.call")) return; diff --git a/src/otel/otel.ts b/src/otel/otel.ts index 25de3ac..5d3e7d3 100644 --- a/src/otel/otel.ts +++ b/src/otel/otel.ts @@ -30,7 +30,7 @@ import { Anonymity } from "../analytics/PosthogAnalytics"; import { Config } from "../config/Config"; import { getSetting, settingsBus } from "../settings/useSetting"; -const SERVICE_NAME_BASE = "element-call"; +const SERVICE_NAME = "element-call"; let sharedInstance: ElementCallOpenTelemetry; @@ -58,7 +58,7 @@ export class ElementCallOpenTelemetry { // This is how we can make Jaeger show a reaonsable service in the dropdown on the left. const providerConfig = { resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: `${SERVICE_NAME_BASE}-unauthenticated`, + [SemanticResourceAttributes.SERVICE_NAME]: SERVICE_NAME, }), }; this._provider = new WebTracerProvider(providerConfig); diff --git a/src/room/GroupCallInspector.tsx b/src/room/GroupCallInspector.tsx index c058297..ad838fb 100644 --- a/src/room/GroupCallInspector.tsx +++ b/src/room/GroupCallInspector.tsx @@ -31,7 +31,12 @@ import { MatrixEvent, IContent } from "matrix-js-sdk/src/models/event"; import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; -import { CallEvent, VoipEvent } from "matrix-js-sdk/src/webrtc/call"; +import { + CallEvent, + CallState, + MatrixCall, + VoipEvent, +} from "matrix-js-sdk/src/webrtc/call"; import styles from "./GroupCallInspector.module.css"; import { SelectInput } from "../input/SelectInput"; @@ -390,10 +395,18 @@ function useGroupCallState( dispatch({ type: ClientEvent.ReceivedVoipEvent, event }); } - function onSendVoipEvent(event: VoipEvent) { + function onSendVoipEvent(event: VoipEvent, call: MatrixCall) { dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event }); - otelGroupCallMembership?.onSendEvent(event); + otelGroupCallMembership?.onSendEvent(call, event); + } + + function onCallStateChange( + newState: CallState, + _: CallState, + call: MatrixCall + ) { + otelGroupCallMembership?.onCallStateChange(call, newState); } function onUndecryptableToDevice(event: MatrixEvent) { @@ -406,8 +419,8 @@ function useGroupCallState( } client.on(RoomStateEvent.Events, onUpdateRoomState); - //groupCall.on("calls_changed", onCallsChanged); groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent); + groupCall.on(CallEvent.State, onCallStateChange); //client.on("state", onCallsChanged); //client.on("hangup", onCallHangup); client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); @@ -417,8 +430,8 @@ function useGroupCallState( return () => { client.removeListener(RoomStateEvent.Events, onUpdateRoomState); - //groupCall.removeListener("calls_changed", onCallsChanged); groupCall.removeListener(CallEvent.SendVoipEvent, onSendVoipEvent); + groupCall.removeListener(CallEvent.State, onCallStateChange); //client.removeListener("state", onCallsChanged); //client.removeListener("hangup", onCallHangup); client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); diff --git a/src/room/useGroupCall.ts b/src/room/useGroupCall.ts index 0b54c82..553d418 100644 --- a/src/room/useGroupCall.ts +++ b/src/room/useGroupCall.ts @@ -173,6 +173,8 @@ export function useGroupCall( }); if (groupCallOTelMembershipGroupCallId !== groupCall.groupCallId) { + if (groupCallOTelMembership) groupCallOTelMembership.dispose(); + // If the user disables analytics, this will stay around until they leave the call // so analytics will be disabled once they leave. if (ElementCallOpenTelemetry.instance) { diff --git a/yarn.lock b/yarn.lock index ddb3fc6..58b450a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1821,7 +1821,7 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== -"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.3": +"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.5": version "0.1.0-alpha.5" resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.5.tgz#60ede2c43b9d808ba8cf46085a3b347b290d9658" integrity sha512-2KjAgWNGfuGLNjJwsrs6gGX157vmcTfNrA4u249utgnMPbJl7QwuUqh1bGxQ0PpK06yvZjgPlkna0lTbuwtuQw== @@ -10545,18 +10545,18 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#23837266fca5ee799b51a722f7b8eefb2f5ac140": - version "23.5.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/23837266fca5ee799b51a722f7b8eefb2f5ac140" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#042f2ed76c501c10dde98a31732fd92d862e2187": + version "24.0.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/042f2ed76c501c10dde98a31732fd92d862e2187" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.3" + "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.5" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4" loglevel "^1.7.1" matrix-events-sdk "0.0.1" - matrix-widget-api "^1.0.0" + matrix-widget-api "^1.3.1" p-retry "4" sdp-transform "^2.14.1" unhomoglyph "^1.0.6" @@ -10570,6 +10570,14 @@ matrix-widget-api@^1.0.0: "@types/events" "^3.0.0" events "^3.2.0" +matrix-widget-api@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.3.1.tgz#e38f404c76bb15c113909505c1c1a5b4d781c2f5" + integrity sha512-+rN6vGvnXm+fn0uq9r2KWSL/aPtehD6ObC50jYmUcEfgo8CUpf9eUurmjbRlwZkWq3XHXFuKQBUCI9UzqWg37Q== + dependencies: + "@types/events" "^3.0.0" + events "^3.2.0" + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" From 4bf1fbfd8ef4f79b56c235093f089ed74805c0b7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 29 Mar 2023 13:31:47 +0100 Subject: [PATCH 08/18] Gah, the sentry logger --- src/otel/OTelGroupCallMembership.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/otel/OTelGroupCallMembership.ts b/src/otel/OTelGroupCallMembership.ts index 4c6d308..432970b 100644 --- a/src/otel/OTelGroupCallMembership.ts +++ b/src/otel/OTelGroupCallMembership.ts @@ -15,13 +15,13 @@ limitations under the License. */ import opentelemetry, { Span, Attributes, Context } from "@opentelemetry/api"; -import { logger } from "@sentry/utils"; import { GroupCall, MatrixClient, MatrixEvent, RoomMember, } from "matrix-js-sdk"; +import { logger } from "matrix-js-sdk/src/logger"; import { CallState, MatrixCall, From 848e28ef925de880dfa98e384f5321da0a44b31d Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 29 Mar 2023 15:51:07 +0100 Subject: [PATCH 09/18] Change allowed origin to https://* as that allows the PR branches out-of-the-box --- config/otel_dev/collector-gateway.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/otel_dev/collector-gateway.yaml b/config/otel_dev/collector-gateway.yaml index 7b1fad0..9c1a9cd 100644 --- a/config/otel_dev/collector-gateway.yaml +++ b/config/otel_dev/collector-gateway.yaml @@ -7,7 +7,8 @@ receivers: allowed_origins: # This can't be '*' because opentelemetry-js uses sendBeacon which always operates # in 'withCredentials' mode, which browsers don't allow with an allow-origin of '*' - - "http://*" + #- "https://pr976--element-call.netlify.app" + - "https://*" allowed_headers: - "*" processors: From f96ce8985d261fecab22aed5b7be21c69ea6b9a9 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 29 Mar 2023 16:04:11 +0100 Subject: [PATCH 10/18] Only enable otel if we have a collector URL --- src/otel/otel.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/otel/otel.ts b/src/otel/otel.ts index 5d3e7d3..eac7ce4 100644 --- a/src/otel/otel.ts +++ b/src/otel/otel.ts @@ -88,12 +88,16 @@ export class ElementCallOpenTelemetry { } function recheckOTelEnabledStatus(optInAnalayticsEnabled: boolean): void { - if (optInAnalayticsEnabled && !sharedInstance) { + const shouldEnable = + optInAnalayticsEnabled && + Boolean(Config.get().opentelemetry?.collector_url); + + if (shouldEnable && !sharedInstance) { logger.info("Starting OpenTelemetry debug reporting"); sharedInstance = new ElementCallOpenTelemetry( Config.get().opentelemetry?.collector_url ); - } else if (!optInAnalayticsEnabled && sharedInstance) { + } else if (!shouldEnable && sharedInstance) { logger.info("Stopping OpenTelemetry debug reporting"); sharedInstance = undefined; } From 21458c8840bdf0cd71b619e2a7911bfc0f93f4b0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 30 Mar 2023 13:03:58 +0100 Subject: [PATCH 11/18] Call the same leave method everywhere So we end the group call span whenever we leasve the call, including if we close the page. --- src/room/useGroupCall.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/room/useGroupCall.ts b/src/room/useGroupCall.ts index 392445f..b591629 100644 --- a/src/room/useGroupCall.ts +++ b/src/room/useGroupCall.ts @@ -202,6 +202,11 @@ export function useGroupCall( [] ); + const leaveCall = useCallback(() => { + groupCallOTelMembership?.onLeaveCall(); + groupCall.leave(); + }, [groupCall]); + useEffect(() => { // disable the media action keys, otherwise audio elements get paused when // the user presses media keys or unplugs headphones, etc. @@ -394,12 +399,12 @@ export function useGroupCall( onParticipantsChanged ); groupCall.removeListener(GroupCallEvent.Error, onError); - groupCall.leave(); + leaveCall(); }; - }, [groupCall, updateState]); + }, [groupCall, updateState, leaveCall]); usePageUnload(() => { - groupCall.leave(); + leaveCall(); }); const initLocalCallFeed = useCallback( @@ -426,11 +431,6 @@ export function useGroupCall( groupCallOTelMembership?.onJoinCall(); }, [groupCall, updateState]); - const leave = useCallback(() => { - groupCallOTelMembership?.onLeaveCall(); - groupCall.leave(); - }, [groupCall]); - const toggleLocalVideoMuted = useCallback(() => { const toggleToMute = !groupCall.isLocalVideoMuted(); groupCall.setLocalVideoMuted(toggleToMute); @@ -563,7 +563,7 @@ export function useGroupCall( error, initLocalCallFeed, enter, - leave, + leave: leaveCall, toggleLocalVideoMuted, toggleMicrophoneMuted, toggleScreensharing, From c2b78d59c6aba34f9cc1f9f98dbc778b2708680d Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 30 Mar 2023 16:54:10 +0100 Subject: [PATCH 12/18] Add more events: * VoIP events received * Call errors * Group call errors * Undecryptable to-device events --- src/otel/OTelGroupCallMembership.ts | 53 +++++++++++++++++++++++++++++ src/room/GroupCallInspector.tsx | 24 ++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/otel/OTelGroupCallMembership.ts b/src/otel/OTelGroupCallMembership.ts index 432970b..53551b0 100644 --- a/src/otel/OTelGroupCallMembership.ts +++ b/src/otel/OTelGroupCallMembership.ts @@ -23,12 +23,14 @@ import { } from "matrix-js-sdk"; import { logger } from "matrix-js-sdk/src/logger"; import { + CallError, CallState, MatrixCall, VoipEvent, } from "matrix-js-sdk/src/webrtc/call"; import { CallsByUserAndDevice, + GroupCallError, GroupCallEvent, } from "matrix-js-sdk/src/webrtc/groupCall"; @@ -216,6 +218,37 @@ export class OTelGroupCallMembership { } } + public onReceivedVoipEvent(event: MatrixEvent) { + // These come straight from CallEventHandler so don't have + // a call already associated (in principle we could receive + // events for calls we don't know about). + const callId = event.getContent().call_id; + if (!callId) { + this.callMembershipSpan?.addEvent("matrix.receive_voip_event_no_callid", { + "sender.userId": event.getSender(), + }); + logger.error("Received call event with no call ID!"); + return; + } + + const call = this.callsByCallId.get(callId); + if (!call) { + this.callMembershipSpan?.addEvent( + "matrix.receive_voip_event_unknown_callid", + { + "sender.userId": event.getSender(), + } + ); + logger.error("Received call event for unknown call ID " + callId); + return; + } + + call.span.addEvent("matrix.receive_voip_event", { + "sender.userId": event.getSender(), + ...flattenVoipEvent(event.getContent()), + }); + } + public onToggleMicrophoneMuted(newValue: boolean) { this.callMembershipSpan?.addEvent("matrix.toggleMicMuted", { "matrix.microphone.muted": newValue, @@ -245,4 +278,24 @@ export class OTelGroupCallMembership { "matrix.screensharing.enabled": newValue, }); } + + public onCallError(error: CallError, call: MatrixCall) { + const callTrackingInfo = this.callsByCallId.get(call.callId); + if (!callTrackingInfo) { + logger.error(`Got error for unknown call ID ${call.callId}`); + return; + } + + callTrackingInfo.span.recordException(error); + } + + public onGroupCallError(error: GroupCallError) { + this.callMembershipSpan?.recordException(error); + } + + public onUndecryptableToDevice(event: MatrixEvent) { + this.callMembershipSpan?.addEvent("matrix.toDevice.undecryptable", { + "sender.userId": event.getSender(), + }); + } } diff --git a/src/room/GroupCallInspector.tsx b/src/room/GroupCallInspector.tsx index ad838fb..ad67c7a 100644 --- a/src/room/GroupCallInspector.tsx +++ b/src/room/GroupCallInspector.tsx @@ -28,12 +28,17 @@ import ReactJson, { CollapsedFieldProps } from "react-json-view"; import mermaid from "mermaid"; import { Item } from "@react-stately/collections"; import { MatrixEvent, IContent } from "matrix-js-sdk/src/models/event"; -import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; +import { + GroupCall, + GroupCallError, + GroupCallEvent, +} from "matrix-js-sdk/src/webrtc/groupCall"; import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { CallEvent, CallState, + CallError, MatrixCall, VoipEvent, } from "matrix-js-sdk/src/webrtc/call"; @@ -393,6 +398,8 @@ function useGroupCallState( function onReceivedVoipEvent(event: MatrixEvent) { dispatch({ type: ClientEvent.ReceivedVoipEvent, event }); + + otelGroupCallMembership?.onReceivedVoipEvent(event); } function onSendVoipEvent(event: VoipEvent, call: MatrixCall) { @@ -409,18 +416,31 @@ function useGroupCallState( otelGroupCallMembership?.onCallStateChange(call, newState); } + function onCallError(error: CallError, call: MatrixCall) { + otelGroupCallMembership.onCallError(error, call); + } + + function onGroupCallError(error: GroupCallError) { + otelGroupCallMembership.onGroupCallError(error); + } + function onUndecryptableToDevice(event: MatrixEvent) { dispatch({ type: ClientEvent.ReceivedVoipEvent, event }); Sentry.captureMessage("Undecryptable to-device Event"); + // probably unnecessary if it's now captured via otel? PosthogAnalytics.instance.eventUndecryptableToDevice.track( groupCall.groupCallId ); + + otelGroupCallMembership.onUndecryptableToDevice(event); } client.on(RoomStateEvent.Events, onUpdateRoomState); groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent); groupCall.on(CallEvent.State, onCallStateChange); + groupCall.on(CallEvent.Error, onCallError); + groupCall.on(GroupCallEvent.Error, onGroupCallError); //client.on("state", onCallsChanged); //client.on("hangup", onCallHangup); client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); @@ -432,6 +452,8 @@ function useGroupCallState( client.removeListener(RoomStateEvent.Events, onUpdateRoomState); groupCall.removeListener(CallEvent.SendVoipEvent, onSendVoipEvent); groupCall.removeListener(CallEvent.State, onCallStateChange); + groupCall.removeListener(CallEvent.Error, onCallError); + groupCall.removeListener(GroupCallEvent.Error, onGroupCallError); //client.removeListener("state", onCallsChanged); //client.removeListener("hangup", onCallHangup); client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); From 74b218af8c436ff18e336db09901c91de095a56e Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 30 Mar 2023 17:19:13 +0100 Subject: [PATCH 13/18] Let otel know we're joining before trying to join Otherwise it starts getting calls being created before the group call span exists and we get call spans not associated with the group call span. --- config/otel_dev/collector-gateway.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/otel_dev/collector-gateway.yaml b/config/otel_dev/collector-gateway.yaml index 9c1a9cd..f9e3b90 100644 --- a/config/otel_dev/collector-gateway.yaml +++ b/config/otel_dev/collector-gateway.yaml @@ -8,7 +8,7 @@ receivers: # This can't be '*' because opentelemetry-js uses sendBeacon which always operates # in 'withCredentials' mode, which browsers don't allow with an allow-origin of '*' #- "https://pr976--element-call.netlify.app" - - "https://*" + - "http://*" allowed_headers: - "*" processors: From 72403d1aeac2bd17e363ea39439e8086de1919f7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 31 Mar 2023 10:26:33 +0100 Subject: [PATCH 14/18] Revert 74b218af8c436ff18e336db09901c91de095a56e Comitted entirely the wrong thing --- config/otel_dev/collector-gateway.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/otel_dev/collector-gateway.yaml b/config/otel_dev/collector-gateway.yaml index f9e3b90..9c1a9cd 100644 --- a/config/otel_dev/collector-gateway.yaml +++ b/config/otel_dev/collector-gateway.yaml @@ -8,7 +8,7 @@ receivers: # This can't be '*' because opentelemetry-js uses sendBeacon which always operates # in 'withCredentials' mode, which browsers don't allow with an allow-origin of '*' #- "https://pr976--element-call.netlify.app" - - "http://*" + - "https://*" allowed_headers: - "*" processors: From 5e6c33b3b5aba9e776d217a3a33f3041e6f9fddf Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 31 Mar 2023 10:30:01 +0100 Subject: [PATCH 15/18] Let otel know we're joining before trying to join Otherwise it starts getting calls being created before the group call span exists and we get call spans not associated with the group call span. (What 74b218af8c436ff18e336db09901c91de095a56e should have been) --- src/room/useGroupCall.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/room/useGroupCall.ts b/src/room/useGroupCall.ts index b591629..7a9f69a 100644 --- a/src/room/useGroupCall.ts +++ b/src/room/useGroupCall.ts @@ -423,12 +423,14 @@ export function useGroupCall( PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId); + // 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(); + groupCall.enter().catch((error) => { console.error(error); updateState({ error }); }); - - groupCallOTelMembership?.onJoinCall(); }, [groupCall, updateState]); const toggleLocalVideoMuted = useCallback(() => { From 773f2e009de5850ccce00d24e2f8c47d88391423 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 31 Mar 2023 10:58:12 +0100 Subject: [PATCH 16/18] Typo --- config/otel_dev/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/otel_dev/README.md b/config/otel_dev/README.md index 8fe102d..ea6c09a 100644 --- a/config/otel_dev/README.md +++ b/config/otel_dev/README.md @@ -1,7 +1,7 @@ # OpenTelemetry Collector for development This directory contains a docker compose file that starts a jaeger all-in-one instance -with an in-memory database, along with a standalong OpenTelemetry collector that forwards +with an in-memory database, along with a standalone OpenTelemetry collector that forwards traces into the jaeger. Jaeger has a built-in OpenTelemetry collector, but it can't be configured to send CORS headers so can't be used from a browser. This sets the config on the collector to send CORS headers. From a1aca7bdf234214fc2dc144ccf5472eb0420f004 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 31 Mar 2023 11:10:05 +0100 Subject: [PATCH 17/18] Fix lying comment --- src/analytics/OtelPosthogExporter.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analytics/OtelPosthogExporter.ts b/src/analytics/OtelPosthogExporter.ts index 4fbfa90..8f9ba26 100644 --- a/src/analytics/OtelPosthogExporter.ts +++ b/src/analytics/OtelPosthogExporter.ts @@ -18,9 +18,10 @@ import { SpanExporter, ReadableSpan } from "@opentelemetry/sdk-trace-base"; import { ExportResult, ExportResultCode } from "@opentelemetry/core"; import { PosthogAnalytics } from "./PosthogAnalytics"; + /** - * This is implementation of {@link SpanExporter} that prints spans to the - * console. This class can be used for diagnostic purposes. + * This is implementation of {@link SpanExporter} that sends spans + * to Posthog */ export class PosthogSpanExporter implements SpanExporter { /** From dc725f90a9b8971e198cfb07c42ec6d5fbcb5ff5 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 31 Mar 2023 11:12:10 +0100 Subject: [PATCH 18/18] Fix confusing comment --- src/config/ConfigOptions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigOptions.ts b/src/config/ConfigOptions.ts index cfaaf77..8b0fae1 100644 --- a/src/config/ConfigOptions.ts +++ b/src/config/ConfigOptions.ts @@ -37,7 +37,8 @@ export interface ConfigOptions { }; /** - * Controls whether to to send OpenTelemetry debugging data to collector + * Sets the URL to send opentelemetry data to. If unset, opentelemetry will + * be disabled. */ opentelemetry?: { collector_url: string;