make it run
This commit is contained in:
@@ -268,19 +268,15 @@ export class CallViewModel {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// CallNotificationLifecycle
|
|
||||||
// consider inlining these!!!
|
|
||||||
private sentCallNotification$ = createSentCallNotification$(
|
|
||||||
this.scope,
|
|
||||||
this.matrixRTCSession,
|
|
||||||
);
|
|
||||||
private receivedDecline$ = createReceivedDecline$(this.matrixRoom);
|
|
||||||
|
|
||||||
private callLifecycle = createCallNotificationLifecycle$({
|
private callLifecycle = createCallNotificationLifecycle$({
|
||||||
scope: this.scope,
|
scope: this.scope,
|
||||||
memberships$: this.memberships$,
|
memberships$: this.memberships$,
|
||||||
sentCallNotification$: this.sentCallNotification$,
|
sentCallNotification$: createSentCallNotification$(
|
||||||
receivedDecline$: this.receivedDecline$,
|
this.scope,
|
||||||
|
this.matrixRTCSession,
|
||||||
|
),
|
||||||
|
receivedDecline$: createReceivedDecline$(this.matrixRoom),
|
||||||
options: this.options,
|
options: this.options,
|
||||||
localUser: { userId: this.userId, deviceId: this.deviceId },
|
localUser: { userId: this.userId, deviceId: this.deviceId },
|
||||||
});
|
});
|
||||||
@@ -331,24 +327,44 @@ export class CallViewModel {
|
|||||||
|
|
||||||
public readonly audioParticipants$ = this.scope.behavior(
|
public readonly audioParticipants$ = this.scope.behavior(
|
||||||
this.matrixLivekitMembers$.pipe(
|
this.matrixLivekitMembers$.pipe(
|
||||||
|
switchMap((membersWithEpoch) => {
|
||||||
|
const members = membersWithEpoch.value;
|
||||||
|
const a$ = combineLatest(
|
||||||
|
members.map((member) =>
|
||||||
|
combineLatest([member.connection$, member.participant$]).pipe(
|
||||||
|
map(([connection, participant]) => {
|
||||||
|
// do not render audio for local participant
|
||||||
|
if (!connection || !participant || participant.isLocal)
|
||||||
|
return null;
|
||||||
|
const livekitRoom = connection.livekitRoom;
|
||||||
|
const url = connection.transport.livekit_service_url;
|
||||||
|
|
||||||
|
return { url, livekitRoom, participant: participant.identity };
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return a$;
|
||||||
|
}),
|
||||||
map((members) =>
|
map((members) =>
|
||||||
members.value.reduce<AudioLivekitItem[]>((acc, curr) => {
|
members.reduce<AudioLivekitItem[]>((acc, curr) => {
|
||||||
const url = curr.connection?.transport.livekit_service_url;
|
if (!curr) return acc;
|
||||||
const livekitRoom = curr.connection?.livekitRoom;
|
|
||||||
const participant = curr.participant?.identity;
|
|
||||||
|
|
||||||
if (!url || !livekitRoom || !participant) return acc;
|
const existing = acc.find((item) => item.url === curr.url);
|
||||||
|
|
||||||
const existing = acc.find((item) => item.url === url);
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.participants.push(participant);
|
existing.participants.push(curr.participant);
|
||||||
} else {
|
} else {
|
||||||
acc.push({ livekitRoom, participants: [participant], url });
|
acc.push({
|
||||||
|
livekitRoom: curr.livekitRoom,
|
||||||
|
participants: [curr.participant],
|
||||||
|
url: curr.url,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}, []),
|
}, []),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
public readonly handsRaised$ = this.scope.behavior(
|
public readonly handsRaised$ = this.scope.behavior(
|
||||||
|
|||||||
@@ -16,14 +16,9 @@ import { type MatrixClient } from "matrix-js-sdk";
|
|||||||
import { combineLatest, distinctUntilChanged, first, from, map } from "rxjs";
|
import { combineLatest, distinctUntilChanged, first, from, map } from "rxjs";
|
||||||
import { logger } from "matrix-js-sdk/lib/logger";
|
import { logger } from "matrix-js-sdk/lib/logger";
|
||||||
import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery";
|
import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery";
|
||||||
import { deepCompare } from "matrix-js-sdk/lib/utils";
|
|
||||||
|
|
||||||
import { type Behavior } from "../../Behavior.ts";
|
import { type Behavior } from "../../Behavior.ts";
|
||||||
import {
|
import { type Epoch, type ObservableScope } from "../../ObservableScope.ts";
|
||||||
Epoch,
|
|
||||||
mapEpoch,
|
|
||||||
type ObservableScope,
|
|
||||||
} from "../../ObservableScope.ts";
|
|
||||||
import { Config } from "../../../config/Config.ts";
|
import { Config } from "../../../config/Config.ts";
|
||||||
import { MatrixRTCTransportMissingError } from "../../../utils/errors.ts";
|
import { MatrixRTCTransportMissingError } from "../../../utils/errors.ts";
|
||||||
import { getSFUConfigWithOpenID } from "../../../livekit/openIDSFU.ts";
|
import { getSFUConfigWithOpenID } from "../../../livekit/openIDSFU.ts";
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
RoomEvent,
|
RoomEvent,
|
||||||
} from "livekit-client";
|
} from "livekit-client";
|
||||||
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
|
import { type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
|
||||||
import { BehaviorSubject, type Observable } from "rxjs";
|
import { BehaviorSubject, map, type Observable } from "rxjs";
|
||||||
import { type Logger } from "matrix-js-sdk/lib/logger";
|
import { type Logger } from "matrix-js-sdk/lib/logger";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -184,7 +184,7 @@ export class Connection {
|
|||||||
* It filters the participants to only those that are associated with a membership that claims to publish on this connection.
|
* It filters the participants to only those that are associated with a membership that claims to publish on this connection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public readonly participantsWithTrack$: Behavior<PublishingParticipant[]>;
|
public readonly participants$: Behavior<PublishingParticipant[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The media transport to connect to.
|
* The media transport to connect to.
|
||||||
@@ -211,13 +211,19 @@ export class Connection {
|
|||||||
this.transport = transport;
|
this.transport = transport;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
|
||||||
this.participantsWithTrack$ = scope.behavior(
|
this.participants$ = scope.behavior(
|
||||||
|
// only tracks remote participants
|
||||||
connectedParticipantsObserver(this.livekitRoom, {
|
connectedParticipantsObserver(this.livekitRoom, {
|
||||||
additionalRoomEvents: [
|
additionalRoomEvents: [
|
||||||
RoomEvent.TrackPublished,
|
RoomEvent.TrackPublished,
|
||||||
RoomEvent.TrackUnpublished,
|
RoomEvent.TrackUnpublished,
|
||||||
],
|
],
|
||||||
}),
|
}).pipe(
|
||||||
|
map((participants) => [
|
||||||
|
this.livekitRoom.localParticipant,
|
||||||
|
...participants,
|
||||||
|
]),
|
||||||
|
),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ export function createConnectionManager$({
|
|||||||
// Map the connections to list of {connection, participants}[]
|
// Map the connections to list of {connection, participants}[]
|
||||||
const listOfConnectionsWithPublishingParticipants =
|
const listOfConnectionsWithPublishingParticipants =
|
||||||
connections.value.map((connection) => {
|
connections.value.map((connection) => {
|
||||||
return connection.participantsWithTrack$.pipe(
|
return connection.participants$.pipe(
|
||||||
map((participants) => ({
|
map((participants) => ({
|
||||||
connection,
|
connection,
|
||||||
participants,
|
participants,
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ export function createMatrixLivekitMembers$({
|
|||||||
new Epoch([membershipsWithTransports, managerData] as const, epoch),
|
new Epoch([membershipsWithTransports, managerData] as const, epoch),
|
||||||
),
|
),
|
||||||
generateItemsWithEpoch(
|
generateItemsWithEpoch(
|
||||||
|
// Generator function.
|
||||||
|
// creates an array of `{key, data}[]`
|
||||||
|
// Each change in the keys (new key, missing key) will result in a call to the factory function.
|
||||||
function* ([membershipsWithTransports, managerData]) {
|
function* ([membershipsWithTransports, managerData]) {
|
||||||
for (const { membership, transport } of membershipsWithTransports) {
|
for (const { membership, transport } of membershipsWithTransports) {
|
||||||
// TODO! cannot use membership.membershipID yet, Currently its hardcoded by the jwt service to
|
// TODO! cannot use membership.membershipID yet, Currently its hardcoded by the jwt service to
|
||||||
@@ -125,8 +128,11 @@ export function createMatrixLivekitMembers$({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Each update where the key of the generator array do not change will result in updates to the `data$` observable in the factory.
|
||||||
(scope, data$, participantId, userId) => {
|
(scope, data$, participantId, userId) => {
|
||||||
const member = matrixRoom.getMember(userId);
|
const member = matrixRoom.getMember(userId);
|
||||||
|
// will only get called once per `participantId, userId` pair.
|
||||||
|
// updates to data$ and as a result to displayName$ and mxcAvatarUrl$ are more frequent.
|
||||||
return {
|
return {
|
||||||
participantId,
|
participantId,
|
||||||
userId,
|
userId,
|
||||||
@@ -134,11 +140,9 @@ export function createMatrixLivekitMembers$({
|
|||||||
displayName$: scope.behavior(
|
displayName$: scope.behavior(
|
||||||
displaynameMap$.pipe(
|
displaynameMap$.pipe(
|
||||||
map((displayNames) => {
|
map((displayNames) => {
|
||||||
const name = displayNames.get(userId);
|
const name = displayNames.get(userId) ?? "";
|
||||||
if (name === undefined) {
|
if (name === "")
|
||||||
logger.warn(`No display name for user ${userId}`);
|
logger.warn(`No display name for user ${userId}`);
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return name;
|
return name;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ Please see LICENSE in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { BehaviorSubject, timer } from "rxjs";
|
import { BehaviorSubject, combineLatest, timer } from "rxjs";
|
||||||
|
import { logger } from "matrix-js-sdk/lib/logger";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Epoch,
|
Epoch,
|
||||||
@@ -72,4 +73,28 @@ describe("Epoch", () => {
|
|||||||
|
|
||||||
scope.behavior(a$, undefined);
|
scope.behavior(a$, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("diamonds emits in a predictable order", () => {
|
||||||
|
const sb$ = new BehaviorSubject("initial");
|
||||||
|
const root$ = sb$.pipe(trackEpoch());
|
||||||
|
const derivedA$ = root$.pipe(mapEpoch((e) => e + "-A"));
|
||||||
|
const derivedB$ = root$.pipe(mapEpoch((e) => e + "-B"));
|
||||||
|
combineLatest([root$, derivedB$, derivedA$]).subscribe(
|
||||||
|
([root, derivedA, derivedB]) => {
|
||||||
|
logger.log(
|
||||||
|
"combined" +
|
||||||
|
root.epoch +
|
||||||
|
root.value +
|
||||||
|
"\n" +
|
||||||
|
derivedA.epoch +
|
||||||
|
derivedA.value +
|
||||||
|
"\n" +
|
||||||
|
derivedB.epoch +
|
||||||
|
derivedB.value,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
sb$.next("updated");
|
||||||
|
sb$.next("ANOTERUPDATE");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user