diff --git a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.test.ts b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.test.ts index 244d70ae8..09c827896 100644 --- a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.test.ts +++ b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.test.ts @@ -5,7 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { describe, test, expect, beforeEach, afterEach } from "vitest"; +import { describe, test, expect, beforeEach, afterEach, vi } from "vitest"; +import { logger } from "matrix-js-sdk/lib/logger"; import { type CallMembership, type LivekitTransport, @@ -77,6 +78,7 @@ function epochMeWith$( } test("should signal participant not yet connected to livekit", async () => { + const info = vi.spyOn(logger, "info"); const mockedMemberships$ = new BehaviorSubject([bobMembership]); const mockConnectionManagerData$ = new BehaviorSubject( new ConnectionManagerData(), @@ -108,6 +110,9 @@ test("should signal participant not yet connected to livekit", async () => { return true; }, ); + expect(info).toHaveBeenCalledWith( + "[RemoteMatrixLivekitMembers] @bob:example.org:DEV000: LiveKit participant missing", + ); }); // Helper to create epoch'ed memberships$ and membershipsWithTransport$ from memberships observable. diff --git a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts index 0b93a274b..e884d3821 100644 --- a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts +++ b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts @@ -11,6 +11,7 @@ import { type LivekitTransportConfig, } from "matrix-js-sdk/lib/matrixrtc"; import { combineLatest, filter, map } from "rxjs"; +import { logger } from "matrix-js-sdk/lib/logger"; import { type Behavior } from "../../Behavior"; import { type IConnectionManager } from "./ConnectionManager"; @@ -133,8 +134,15 @@ export function createRemoteMatrixLivekitMembers$({ } }, // Each update where the key of the generator array do not change will result in updates to the `data$` behavior. - (scope, data$, userId, _deviceId, _memberId, _rtcBackendIdentity) => { + (scope, data$, userId, _deviceId, _memberId, rtcBackendIdentity) => { const { participant$, ...rest } = scope.splitBehavior(data$); + // Log whether the member could be matched to a LiveKit participant, + // since a tile shows "waiting for media" for as long as it cannot. + participant$.pipe(scope.bind()).subscribe((p) => { + logger.info( + `[RemoteMatrixLivekitMembers] ${rtcBackendIdentity}: LiveKit participant ${p ? `matched (${p.sid})` : "missing"}`, + ); + }); // will only get called once per backend identity. // updates to data$ and as a result to displayName$ and mxcAvatarUrl$ are more frequent. return { diff --git a/src/state/media/RemoteUserMediaViewModel.ts b/src/state/media/RemoteUserMediaViewModel.ts index 4307dea41..6daa381a7 100644 --- a/src/state/media/RemoteUserMediaViewModel.ts +++ b/src/state/media/RemoteUserMediaViewModel.ts @@ -8,6 +8,7 @@ Please see LICENSE in the repository root for full details. import { type RemoteParticipant } from "livekit-client"; import { combineLatest, map, of, switchMap } from "rxjs"; +import { logger } from "matrix-js-sdk/lib/logger"; import { type Behavior } from "../Behavior"; import { createVolumeControls, type VolumeControls } from "../VolumeControls"; @@ -45,6 +46,20 @@ export function createRemoteUserMedia( statsType: "inbound-rtp", }); + const waitingForMedia$ = scope.behavior( + combineLatest( + [inputs.livekitRoom$, inputs.participant$], + (livekitRoom, participant) => + // If livekitRoom is undefined, the user is not attempting to publish on + // any transport and so we shouldn't expect a participant. (They might + // be a subscribe-only bot for example.) + livekitRoom !== undefined && participant === null, + ), + ); + waitingForMedia$.pipe(scope.bind()).subscribe((waiting) => { + logger.info(`[RemoteUserMedia ${inputs.id}] waitingForMedia=${waiting}`); + }); + return { ...baseUserMedia, ...createVolumeControls(scope, { @@ -68,15 +83,6 @@ export function createRemoteUserMedia( ), ), ), - waitingForMedia$: scope.behavior( - combineLatest( - [inputs.livekitRoom$, inputs.participant$], - (livekitRoom, participant) => - // If livekitRoom is undefined, the user is not attempting to publish on - // any transport and so we shouldn't expect a participant. (They might - // be a subscribe-only bot for example.) - livekitRoom !== undefined && participant === null, - ), - ), + waitingForMedia$, }; }