mirror of
https://github.com/vector-im/element-call.git
synced 2026-10-16 23:45:50 +00:00
Take the word call out of the member API
membership$ is typed as RTCMembership, the subset of the js-sdk CallMembership that hosts read. UnknownCallError is UnknownRTCError throughout, not only in the export. applicationData reaches the membership whole, since the js-sdk takes it next to the intent. The plan records the three slices as implemented. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
b9f79be106
commit
6bd6e3f953
+13
-12
@@ -383,8 +383,7 @@ No behaviour change; one PR of renames and type narrowing.
|
|||||||
|
|
||||||
## Changed behaviour
|
## Changed behaviour
|
||||||
|
|
||||||
What a host sees differently, per slice. The first block is implemented; the
|
What a host sees differently, per slice. All four blocks are implemented.
|
||||||
rest follows the slices above and is marked as planned.
|
|
||||||
|
|
||||||
### `tracks$` and `isActive$` (this plan, implemented)
|
### `tracks$` and `isActive$` (this plan, implemented)
|
||||||
|
|
||||||
@@ -416,19 +415,20 @@ Differences in what the values mean:
|
|||||||
before had an order.
|
before had an order.
|
||||||
- The harness labels audio elements with `data-active`. Test ids are unchanged.
|
- The harness labels audio elements with `data-active`. Test ids are unchanged.
|
||||||
|
|
||||||
### Slice 1, local track controls (planned)
|
### Slice 1, local track controls
|
||||||
|
|
||||||
- `switchCamera()` on the local media becomes `switchFacingMode()` on the local
|
- `switchCamera()` on the local media becomes `switchFacingMode()` on the local
|
||||||
camera track; it rejects, instead of resolving `undefined`, when there is no
|
camera track, so there is always a track to call it on; it still resolves
|
||||||
camera track.
|
`undefined` where the facing mode is unknown.
|
||||||
- Input device and processor changes are calls on the track. The SDK no longer
|
- Input device and processor changes are calls on the track. The SDK no longer
|
||||||
reacts to `audioInputDeviceId$`, `videoInputDeviceId$` or `videoProcessor$`;
|
reacts to `audioInputDeviceId$`, `videoInputDeviceId$` or `videoProcessor$`;
|
||||||
a host that changed a setting and expected the SDK to follow now calls
|
a host that changed a setting and expected the SDK to follow now calls
|
||||||
`setDevice` or `setProcessor` itself.
|
`setDevice` or `setProcessor` itself. The initial device and processor travel
|
||||||
|
with the publish request instead.
|
||||||
- `setEnabled(false)` on a local track mutes it and keeps the publication, as
|
- `setEnabled(false)` on a local track mutes it and keeps the publication, as
|
||||||
`setMicrophoneEnabled(false)` does today.
|
`setMicrophoneEnabled(false)` does today.
|
||||||
|
|
||||||
### Slice 2, `publish` and `unpublish` (planned)
|
### Slice 2, `publish` and `unpublish`
|
||||||
|
|
||||||
- Screen sharing is `publish({ source: "screenShare" })` and `unpublish(id)`.
|
- Screen sharing is `publish({ source: "screenShare" })` and `unpublish(id)`.
|
||||||
A capture failure rejects the promise; there is no `screenShareError$` to
|
A capture failure rejects the promise; there is no `screenShareError$` to
|
||||||
@@ -444,12 +444,13 @@ false, cameraEnabled: false` before.
|
|||||||
- Capture settings travel with each request. A host that set
|
- Capture settings travel with each request. A host that set
|
||||||
`capture.screenShare` once sets it on each screen share publish instead.
|
`capture.screenShare` once sets it on each screen share publish instead.
|
||||||
|
|
||||||
### Slice 3, names (planned)
|
### Slice 3, names
|
||||||
|
|
||||||
- `membership$` is typed as `RTCMembership`. A host that reached for a
|
- `membership$` is typed as `RTCMembership`. A host that reached for a
|
||||||
`CallMembership` member outside the narrowed set must import the js-sdk type
|
`CallMembership` member outside the narrowed set must import the js-sdk type
|
||||||
itself; the object is unchanged.
|
itself; the object is unchanged.
|
||||||
- `UnknownCallError` is renamed; `index.ts` stops exporting it as
|
- `UnknownCallError` is `UnknownRTCError` in the SDK too, not only in the
|
||||||
`UnknownRTCError`. Error codes do not change.
|
export. Error codes do not change. The two `Livekit*` errors are left to
|
||||||
- `applicationData` is forwarded whole once the js-sdk takes it. Until then the
|
slice 11 of `SdkMigration.md`, which renames them on both sides at once.
|
||||||
behaviour is as today: only `m.call.intent` reaches the membership.
|
- `applicationData` is forwarded whole: the js-sdk takes it next to
|
||||||
|
`m.call.intent`, which the membership format carries as a field of its own.
|
||||||
|
|||||||
+21
-6
@@ -115,7 +115,7 @@ without anyone hearing it. `leave()` pauses the upstream again and sends the lea
|
|||||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
||||||
| client | a `MatrixRTCClient`: one room, one slot, one local member | `MatrixClient` is always written out |
|
| client | a `MatrixRTCClient`: one room, one slot, one local member | `MatrixClient` is always written out |
|
||||||
| session | the MatrixRTC session in the room: the set of memberships. Only used for the js-sdk object, which stays inside the SDK as `JsSdkRTCSession` | MSC4143 |
|
| session | the MatrixRTC session in the room: the set of memberships. Only used for the js-sdk object, which stays inside the SDK as `JsSdkRTCSession` | MSC4143 |
|
||||||
| membership | one device's MatrixRTC state event, the js-sdk `CallMembership`. The js-sdk name is kept until it renames it | |
|
| membership | one device's MatrixRTC state event, seen by hosts as `RTCMembership`, the js-sdk `CallMembership` behind it | |
|
||||||
| member | an `RTCMember`: a membership plus what the SDK derives from it (display name, transport, media) | Element Call's "matrixLivekitMember" |
|
| member | an `RTCMember`: a membership plus what the SDK derives from it (display name, transport, media) | Element Call's "matrixLivekitMember" |
|
||||||
| participant | a LiveKit participant, the media side of a member. Never leaves the SDK | |
|
| participant | a LiveKit participant, the media side of a member. Never leaves the SDK | |
|
||||||
| transport | where media is exchanged: a LiveKit service url today, described by `TransportMetadata` | MSC4143 "focus" |
|
| transport | where media is exchanged: a LiveKit service url today, described by `TransportMetadata` | MSC4143 "focus" |
|
||||||
@@ -334,7 +334,23 @@ export interface DataMessage {
|
|||||||
### Members
|
### Members
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { type CallMembership } from "matrix-js-sdk/lib/matrixrtc";
|
/**
|
||||||
|
* What a membership says, as hosts read it. The js-sdk `CallMembership` is
|
||||||
|
* behind it; anything beyond this is the js-sdk's API, not the SDK's.
|
||||||
|
*/
|
||||||
|
export type RTCMembership = Pick<
|
||||||
|
CallMembership,
|
||||||
|
| "userId"
|
||||||
|
| "deviceId"
|
||||||
|
| "memberId"
|
||||||
|
| "rtcBackendIdentity"
|
||||||
|
| "application"
|
||||||
|
| "applicationData"
|
||||||
|
| "getTransport"
|
||||||
|
| "transports"
|
||||||
|
| "createdTs"
|
||||||
|
| "getAbsoluteExpiry"
|
||||||
|
>;
|
||||||
|
|
||||||
export interface RTCMember {
|
export interface RTCMember {
|
||||||
local: boolean;
|
local: boolean;
|
||||||
@@ -346,7 +362,7 @@ export interface RTCMember {
|
|||||||
id: string;
|
id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
membership$: Behavior<CallMembership>;
|
membership$: Behavior<RTCMembership>;
|
||||||
/**
|
/**
|
||||||
* Matrix room state rather than MatrixRTC, but the SDK already holds the
|
* Matrix room state rather than MatrixRTC, but the SDK already holds the
|
||||||
* room and every consumer wants them next to the membership. Disambiguated
|
* room and every consumer wants them next to the membership. Disambiguated
|
||||||
@@ -658,9 +674,8 @@ public API only.
|
|||||||
|
|
||||||
- **Publishing before `join()`.** The initial requests are published at the
|
- **Publishing before `join()`.** The initial requests are published at the
|
||||||
join; creating the tracks earlier, for a lobby preview, is still missing.
|
join; creating the tracks earlier, for a lobby preview, is still missing.
|
||||||
- **`applicationData` after the join.** The option is read once. The client
|
- **`applicationData` after the join.** The option is read once; there is no
|
||||||
still updates `m.call.intent` from the camera state, as Element Call did; that
|
way to update it on a live membership yet.
|
||||||
moves to the host once the data can be updated.
|
|
||||||
- **Raw local state.** The local member's state machine (`LocalMemberState`) stays
|
- **Raw local state.** The local member's state machine (`LocalMemberState`) stays
|
||||||
internal; `status$`, `disconnectReason$` and `fatalError$` are its public view.
|
internal; `status$`, `disconnectReason$` and `fatalError$` are its public view.
|
||||||
A developer panel may want it as `LocalRTCMember.state$`.
|
A developer panel may want it as `LocalRTCMember.state$`.
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ export {
|
|||||||
NoMatrix2AuthorizationService,
|
NoMatrix2AuthorizationService,
|
||||||
PeerConnectionTimeoutError,
|
PeerConnectionTimeoutError,
|
||||||
SFURoomCreationRestrictedError,
|
SFURoomCreationRestrictedError,
|
||||||
UnknownCallError as UnknownRTCError,
|
UnknownRTCError,
|
||||||
} from "./src/errors";
|
} from "./src/errors";
|
||||||
|
|
||||||
export * from "./src/api";
|
export * from "./src/api";
|
||||||
|
|||||||
+23
-4
@@ -48,9 +48,10 @@ export interface MatrixRTCClientOptions {
|
|||||||
/** The application's slot in the room. Default `ROOM`. */
|
/** The application's slot in the room. Default `ROOM`. */
|
||||||
slot?: string;
|
slot?: string;
|
||||||
/**
|
/**
|
||||||
* Whatever the application wants to say about itself in the membership.
|
* Whatever the application wants to say about itself in the membership,
|
||||||
* Opaque to the SDK. Today the js-sdk carries one key, `m.call.intent`
|
* under namespaced keys. Opaque to the SDK, apart from `m.call.intent`
|
||||||
* (`"audio"` or `"video"`); anything else is dropped until it can.
|
* (`"audio"` or `"video"`), which the membership format carries as a
|
||||||
|
* field of its own.
|
||||||
*/
|
*/
|
||||||
applicationData?: Record<string, unknown>;
|
applicationData?: Record<string, unknown>;
|
||||||
/** Session timings the host has configured; the defaults otherwise. */
|
/** Session timings the host has configured; the defaults otherwise. */
|
||||||
@@ -211,13 +212,31 @@ export type ResolvedTransport =
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Members
|
// Members
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What a membership says, as hosts read it. The js-sdk `CallMembership` is
|
||||||
|
* behind it; anything beyond this is the js-sdk's API, not the SDK's.
|
||||||
|
*/
|
||||||
|
export type RTCMembership = Pick<
|
||||||
|
CallMembership,
|
||||||
|
| "userId"
|
||||||
|
| "deviceId"
|
||||||
|
| "memberId"
|
||||||
|
| "rtcBackendIdentity"
|
||||||
|
| "application"
|
||||||
|
| "applicationData"
|
||||||
|
| "getTransport"
|
||||||
|
| "transports"
|
||||||
|
| "createdTs"
|
||||||
|
| "getAbsoluteExpiry"
|
||||||
|
>;
|
||||||
|
|
||||||
export interface RTCMember {
|
export interface RTCMember {
|
||||||
local: boolean;
|
local: boolean;
|
||||||
/** The identity the media backend knows this member by. */
|
/** The identity the media backend knows this member by. */
|
||||||
id: string;
|
id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
membership$: Behavior<CallMembership>;
|
membership$: Behavior<RTCMembership>;
|
||||||
displayName$: Behavior<string>;
|
displayName$: Behavior<string>;
|
||||||
avatarUrl$: Behavior<string | undefined>;
|
avatarUrl$: Behavior<string | undefined>;
|
||||||
/** Which transport this member is on; undefined when the membership has none. */
|
/** Which transport this member is on; undefined when the membership has none. */
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ export class MembershipManagerError extends MatrixRTCError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UnknownCallError extends MatrixRTCError {
|
export class UnknownRTCError extends MatrixRTCError {
|
||||||
public constructor(cause: Error) {
|
public constructor(cause: Error) {
|
||||||
super(
|
super(
|
||||||
cause.message || "Unknown error",
|
cause.message || "Unknown error",
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import {
|
|||||||
LivekitConnectionError,
|
LivekitConnectionError,
|
||||||
PeerConnectionTimeoutError,
|
PeerConnectionTimeoutError,
|
||||||
SFURoomCreationRestrictedError,
|
SFURoomCreationRestrictedError,
|
||||||
UnknownCallError,
|
UnknownRTCError,
|
||||||
} from "../errors";
|
} from "../errors";
|
||||||
|
|
||||||
export interface ConnectionOpts {
|
export interface ConnectionOpts {
|
||||||
@@ -381,8 +381,8 @@ export class Connection {
|
|||||||
error instanceof MatrixRTCError
|
error instanceof MatrixRTCError
|
||||||
? error
|
? error
|
||||||
: error instanceof Error
|
: error instanceof Error
|
||||||
? new UnknownCallError(error)
|
? new UnknownRTCError(error)
|
||||||
: new UnknownCallError(new Error(`${error}`)),
|
: new UnknownRTCError(new Error(`${error}`)),
|
||||||
);
|
);
|
||||||
// Its okay to ignore the throw. The error is part of the state.
|
// Its okay to ignore the throw. The error is part of the state.
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ export function joinJsSdkSession(
|
|||||||
delayedLeave,
|
delayedLeave,
|
||||||
}: Options,
|
}: Options,
|
||||||
): void {
|
): void {
|
||||||
// The one piece of application data the js-sdk can put in a membership
|
// The membership format carries the intent as a field of its own
|
||||||
const intent = applicationData?.["m.call.intent"];
|
const { "m.call.intent": intent, ...rest } = applicationData ?? {};
|
||||||
const callIntent =
|
const callIntent =
|
||||||
typeof intent === "string" ? (intent as RTCCallIntent) : undefined;
|
typeof intent === "string" ? (intent as RTCCallIntent) : undefined;
|
||||||
// Give up on the network as soon as either the sync has been down for the
|
// Give up on the network as soon as either the sync has been down for the
|
||||||
@@ -61,6 +61,7 @@ export function joinJsSdkSession(
|
|||||||
session.joinRTCSession(ownMembershipIdentity, [transport], {
|
session.joinRTCSession(ownMembershipIdentity, [transport], {
|
||||||
notificationType: sendNotificationType,
|
notificationType: sendNotificationType,
|
||||||
callIntent,
|
callIntent,
|
||||||
|
applicationData: rest,
|
||||||
manageMediaKeys: encryptMedia,
|
manageMediaKeys: encryptMedia,
|
||||||
delayedLeaveEventRestartMs: delayedLeave.restart_ms,
|
delayedLeaveEventRestartMs: delayedLeave.restart_ms,
|
||||||
delayedLeaveEventDelayMs: delayedLeave.delay_ms,
|
delayedLeaveEventDelayMs: delayedLeave.delay_ms,
|
||||||
|
|||||||
Reference in New Issue
Block a user