Skip to content

Commit 3ea785b

Browse files
committed
handle slot assignment
1 parent 4fa2168 commit 3ea785b

File tree

1 file changed

+69
-20
lines changed

1 file changed

+69
-20
lines changed

client-web/src/lib/core.ts

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { ClientMessage, MediaConfig, ServerMessage } from "./sfu.ts";
1+
import {
2+
ClientMessage,
3+
MediaConfig,
4+
ParticipantStream,
5+
ParticipantSubscription,
6+
ServerMessage,
7+
VideoSubscription,
8+
} from "./sfu.ts";
29

310
const MAX_DOWNSTREAMS = 16;
411
const LAST_N_AUDIO = 3;
@@ -13,7 +20,8 @@ interface VideoSlot {
1320

1421
interface ParticipantMeta {
1522
externalParticipantId: string;
16-
media?: MediaConfig;
23+
participantId: string;
24+
media: MediaConfig;
1725
}
1826

1927
export interface ClientCoreConfig {
@@ -28,6 +36,7 @@ export class ClientCore {
2836
#videoSender: RTCRtpTransceiver;
2937
#audioSender: RTCRtpTransceiver;
3038
#closed: boolean;
39+
#sequence: number;
3140

3241
#videoSlots: VideoSlot[];
3342
#audioSlots: RTCRtpTransceiver[];
@@ -47,6 +56,7 @@ export class ClientCore {
4756
this.#videoSlots = [];
4857
this.#audioSlots = [];
4958
this.#participants = {};
59+
this.#sequence = 0;
5060

5161
this.#pc = new RTCPeerConnection();
5262
this.#pc.onconnectionstatechange = () => {
@@ -81,27 +91,13 @@ export class ClientCore {
8191

8292
switch (msgKind) {
8393
case "roomSnapshot":
84-
for (const participant of msg.roomSnapshot.participants) {
85-
this.#participants[participant.participantId] = {
86-
externalParticipantId: participant.externalParticipantId,
87-
media: participant.media,
88-
};
89-
}
94+
this.#handleParticipantUpdates(msg.roomSnapshot.participants);
9095
break;
9196
case "streamUpdate":
9297
if (msg.streamUpdate.participantStream) {
93-
const stream = msg.streamUpdate.participantStream;
94-
if (stream.participantId in this.#participants) {
95-
const participant = this.#participants[stream.participantId];
96-
participant.media = stream.media;
97-
participant.externalParticipantId =
98-
stream.externalParticipantId;
99-
} else {
100-
this.#participants[stream.participantId] = {
101-
externalParticipantId: stream.externalParticipantId,
102-
media: stream.media,
103-
};
104-
}
98+
this.#handleParticipantUpdates([
99+
msg.streamUpdate.participantStream,
100+
]);
105101
}
106102
break;
107103
}
@@ -138,6 +134,59 @@ export class ClientCore {
138134
}
139135
}
140136

137+
#sendRpc(msg: ClientMessage["msg"]) {
138+
this.#rpc.send(ClientMessage.toBinary({
139+
sequence: this.#sequence,
140+
msg,
141+
}));
142+
this.#sequence += 1;
143+
}
144+
145+
#handleParticipantUpdates(streams: ParticipantStream[]) {
146+
const newParticipants: ParticipantMeta[] = [];
147+
148+
for (const stream of streams) {
149+
if (!stream.media) {
150+
// participant has left
151+
delete this.#participants[stream.participantId];
152+
continue;
153+
}
154+
155+
if (stream.participantId in this.#participants) {
156+
const participant = this.#participants[stream.participantId];
157+
participant.media = stream.media;
158+
participant.externalParticipantId = stream.externalParticipantId;
159+
participant.participantId = stream.participantId;
160+
} else {
161+
const meta: ParticipantMeta = {
162+
externalParticipantId: stream.externalParticipantId,
163+
participantId: stream.participantId,
164+
media: stream.media,
165+
};
166+
this.#participants[stream.participantId] = meta;
167+
newParticipants.push(meta);
168+
}
169+
}
170+
171+
// TODO: should we bin pack the old participants first?
172+
for (const slot of this.#videoSlots) {
173+
if (slot.participantId) {
174+
if (slot.participantId in this.#participants) {
175+
continue;
176+
}
177+
178+
slot.participantId = undefined;
179+
}
180+
181+
const participant = newParticipants.pop();
182+
if (!participant) {
183+
continue;
184+
}
185+
186+
slot.participantId = participant.participantId;
187+
}
188+
}
189+
141190
#close(error?: string) {
142191
if (this.#closed) return;
143192

0 commit comments

Comments
 (0)