mirror of
https://github.com/vector-im/element-call.git
synced 2026-02-05 04:15:58 +00:00
ideas
This commit is contained in:
@@ -452,14 +452,18 @@ export function createCallViewModel$(
|
||||
|
||||
const localMembership = createLocalMembership$({
|
||||
scope: scope,
|
||||
homeserverConnected: createHomeserverConnected$(
|
||||
homeserverConnected$: createHomeserverConnected$(
|
||||
scope,
|
||||
client,
|
||||
matrixRTCSession,
|
||||
),
|
||||
muteStates: muteStates,
|
||||
joinMatrixRTC: (transport: LivekitTransport) => {
|
||||
enterRTCSession(matrixRTCSession, transport, connectOptions$.value);
|
||||
joinMatrixRTC: async (transport: LivekitTransport) => {
|
||||
return enterRTCSession(
|
||||
matrixRTCSession,
|
||||
transport,
|
||||
connectOptions$.value,
|
||||
);
|
||||
},
|
||||
createPublisherFactory: (connection: Connection) => {
|
||||
return new Publisher(
|
||||
@@ -569,6 +573,17 @@ export function createCallViewModel$(
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Whether various media/event sources should pretend to be disconnected from
|
||||
* all network input, even if their connection still technically works.
|
||||
*/
|
||||
// We do this when the app is in the 'reconnecting' state, because it might be
|
||||
// that the LiveKit connection is still functional while the homeserver is
|
||||
// down, for example, and we want to avoid making people worry that the app is
|
||||
// in a split-brained state.
|
||||
// DISCUSSION own membership manager ALSO this probably can be simplifis
|
||||
const reconnecting$ = localMembership.reconnecting$;
|
||||
|
||||
const audioParticipants$ = scope.behavior(
|
||||
matrixLivekitMembers$.pipe(
|
||||
switchMap((membersWithEpoch) => {
|
||||
@@ -616,7 +631,7 @@ export function createCallViewModel$(
|
||||
);
|
||||
|
||||
const handsRaised$ = scope.behavior(
|
||||
handsRaisedSubject$.pipe(pauseWhen(localMembership.reconnecting$)),
|
||||
handsRaisedSubject$.pipe(pauseWhen(reconnecting$)),
|
||||
);
|
||||
|
||||
const reactions$ = scope.behavior(
|
||||
@@ -629,7 +644,7 @@ export function createCallViewModel$(
|
||||
]),
|
||||
),
|
||||
),
|
||||
pauseWhen(localMembership.reconnecting$),
|
||||
pauseWhen(reconnecting$),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -720,7 +735,7 @@ export function createCallViewModel$(
|
||||
livekitRoom$,
|
||||
focusUrl$,
|
||||
mediaDevices,
|
||||
localMembership.reconnecting$,
|
||||
reconnecting$,
|
||||
displayName$,
|
||||
matrixMemberMetadataStore.createAvatarUrlBehavior$(userId),
|
||||
handsRaised$.pipe(map((v) => v[participantId]?.time ?? null)),
|
||||
@@ -812,17 +827,11 @@ export function createCallViewModel$(
|
||||
}),
|
||||
);
|
||||
|
||||
const shouldLeave$: Observable<
|
||||
"user" | "timeout" | "decline" | "allOthersLeft"
|
||||
> = merge(
|
||||
autoLeave$,
|
||||
merge(userHangup$, widgetHangup$).pipe(map(() => "user" as const)),
|
||||
).pipe(scope.share);
|
||||
|
||||
shouldLeave$.pipe(scope.bind()).subscribe((reason) => {
|
||||
logger.info(`Call left due to ${reason}`);
|
||||
localMembership.requestDisconnect();
|
||||
});
|
||||
const leave$: Observable<"user" | "timeout" | "decline" | "allOthersLeft"> =
|
||||
merge(
|
||||
autoLeave$,
|
||||
merge(userHangup$, widgetHangup$).pipe(map(() => "user" as const)),
|
||||
).pipe(scope.share);
|
||||
|
||||
const spotlightSpeaker$ = scope.behavior<UserMediaViewModel | null>(
|
||||
userMedia$.pipe(
|
||||
@@ -1444,7 +1453,7 @@ export function createCallViewModel$(
|
||||
autoLeave$: autoLeave$,
|
||||
callPickupState$: callPickupState$,
|
||||
ringOverlay$: ringOverlay$,
|
||||
leave$: shouldLeave$,
|
||||
leave$: leave$,
|
||||
hangup: (): void => userHangup$.next(),
|
||||
join: localMembership.requestConnect,
|
||||
toggleScreenSharing: toggleScreenSharing,
|
||||
@@ -1491,7 +1500,7 @@ export function createCallViewModel$(
|
||||
showFooter$: showFooter$,
|
||||
earpieceMode$: earpieceMode$,
|
||||
audioOutputSwitcher$: audioOutputSwitcher$,
|
||||
reconnecting$: localMembership.reconnecting$,
|
||||
reconnecting$: reconnecting$,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "@livekit/components-core";
|
||||
import {
|
||||
ConnectionError,
|
||||
type ConnectionState as LivekitConnectionState,
|
||||
ConnectionState as LivekitConnectionState,
|
||||
type Room as LivekitRoom,
|
||||
type LocalParticipant,
|
||||
type RemoteParticipant,
|
||||
@@ -47,17 +47,24 @@ export interface ConnectionOpts {
|
||||
/** Optional factory to create the LiveKit room, mainly for testing purposes. */
|
||||
livekitRoomFactory: () => LivekitRoom;
|
||||
}
|
||||
export enum ConnectionAdditionalState {
|
||||
export class FailedToStartError extends Error {
|
||||
public constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "FailedToStartError";
|
||||
}
|
||||
}
|
||||
|
||||
export enum ConnectionState {
|
||||
Initialized = "Initialized",
|
||||
FetchingConfig = "FetchingConfig",
|
||||
// FailedToStart = "FailedToStart",
|
||||
Stopped = "Stopped",
|
||||
ConnectingToLkRoom = "ConnectingToLkRoom",
|
||||
LivekitDisconnected = "disconnected",
|
||||
LivekitConnecting = "connecting",
|
||||
LivekitConnected = "connected",
|
||||
LivekitReconnecting = "reconnecting",
|
||||
LivekitSignalReconnecting = "signalReconnecting",
|
||||
}
|
||||
export type ConnectionState =
|
||||
| { state: ConnectionAdditionalState }
|
||||
| { state: LivekitConnectionState }
|
||||
| { state: "FailedToStart"; error: Error };
|
||||
|
||||
/**
|
||||
* A connection to a Matrix RTC LiveKit backend.
|
||||
@@ -66,14 +73,15 @@ export type ConnectionState =
|
||||
*/
|
||||
export class Connection {
|
||||
// Private Behavior
|
||||
private readonly _state$ = new BehaviorSubject<ConnectionState>({
|
||||
state: ConnectionAdditionalState.Initialized,
|
||||
});
|
||||
private readonly _state$ = new BehaviorSubject<
|
||||
ConnectionState | FailedToStartError
|
||||
>(ConnectionState.Initialized);
|
||||
|
||||
/**
|
||||
* The current state of the connection to the media transport.
|
||||
*/
|
||||
public readonly state$: Behavior<ConnectionState> = this._state$;
|
||||
public readonly state$: Behavior<ConnectionState | FailedToStartError> =
|
||||
this._state$;
|
||||
|
||||
/**
|
||||
* The media transport to connect to.
|
||||
@@ -117,16 +125,12 @@ export class Connection {
|
||||
this.logger.debug("Starting Connection");
|
||||
this.stopped = false;
|
||||
try {
|
||||
this._state$.next({
|
||||
state: ConnectionAdditionalState.FetchingConfig,
|
||||
});
|
||||
this._state$.next(ConnectionState.FetchingConfig);
|
||||
const { url, jwt } = await this.getSFUConfigWithOpenID();
|
||||
// If we were stopped while fetching the config, don't proceed to connect
|
||||
if (this.stopped) return;
|
||||
|
||||
this._state$.next({
|
||||
state: ConnectionAdditionalState.ConnectingToLkRoom,
|
||||
});
|
||||
this._state$.next(ConnectionState.ConnectingToLkRoom);
|
||||
try {
|
||||
await this.livekitRoom.connect(url, jwt);
|
||||
} catch (e) {
|
||||
@@ -157,9 +161,8 @@ export class Connection {
|
||||
connectionStateObserver(this.livekitRoom)
|
||||
.pipe(this.scope.bind())
|
||||
.subscribe((lkState) => {
|
||||
this._state$.next({
|
||||
state: lkState,
|
||||
});
|
||||
// It si save to cast lkState to ConnectionState as they are fully overlapping.
|
||||
this._state$.next(lkState as unknown as ConnectionState);
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.debug(`Failed to connect to LiveKit room: ${error}`);
|
||||
|
||||
Reference in New Issue
Block a user