livekit-client 1.6.6 → 1.6.8
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/livekit-client.esm.mjs +508 -317
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/proto/google/protobuf/timestamp.d.ts +9 -2
- package/dist/src/proto/google/protobuf/timestamp.d.ts.map +1 -1
- package/dist/src/proto/livekit_models.d.ts +958 -58
- package/dist/src/proto/livekit_models.d.ts.map +1 -1
- package/dist/src/proto/livekit_rtc.d.ts +8394 -3725
- package/dist/src/proto/livekit_rtc.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +10 -3
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +18 -0
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +2 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +10 -2
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +7 -0
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/ts4.2/src/proto/google/protobuf/timestamp.d.ts +11 -2
- package/dist/ts4.2/src/proto/livekit_models.d.ts +1199 -177
- package/dist/ts4.2/src/proto/livekit_rtc.d.ts +9260 -4023
- package/dist/ts4.2/src/room/RTCEngine.d.ts +10 -3
- package/dist/ts4.2/src/room/Room.d.ts +1 -1
- package/dist/ts4.2/src/room/events.d.ts +1 -1
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +18 -0
- package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +1 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +2 -1
- package/dist/ts4.2/src/room/track/options.d.ts +10 -2
- package/dist/ts4.2/src/room/types.d.ts +7 -0
- package/dist/ts4.2/src/version.d.ts +1 -1
- package/package.json +14 -14
- package/src/proto/google/protobuf/timestamp.ts +4 -0
- package/src/proto/livekit_models.ts +128 -31
- package/src/proto/livekit_rtc.ts +262 -161
- package/src/room/PCTransport.ts +2 -0
- package/src/room/RTCEngine.ts +50 -55
- package/src/room/Room.ts +60 -43
- package/src/room/events.ts +1 -1
- package/src/room/participant/LocalParticipant.ts +118 -28
- package/src/room/participant/RemoteParticipant.ts +2 -3
- package/src/room/track/RemoteTrackPublication.ts +3 -2
- package/src/room/track/RemoteVideoTrack.ts +0 -3
- package/src/room/track/Track.ts +2 -1
- package/src/room/track/options.ts +14 -2
- package/src/room/types.ts +9 -0
- package/src/version.ts +1 -1
package/src/room/PCTransport.ts
CHANGED
package/src/room/RTCEngine.ts
CHANGED
@@ -118,8 +118,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
118
118
|
|
119
119
|
private clientConfiguration?: ClientConfiguration;
|
120
120
|
|
121
|
-
private connectedServerAddr?: string;
|
122
|
-
|
123
121
|
private attemptingReconnect: boolean = false;
|
124
122
|
|
125
123
|
private reconnectPolicy: ReconnectPolicy;
|
@@ -136,6 +134,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
136
134
|
|
137
135
|
private closingLock: Mutex;
|
138
136
|
|
137
|
+
private shouldFailNext: boolean = false;
|
138
|
+
|
139
139
|
constructor(private options: InternalRoomOptions) {
|
140
140
|
super();
|
141
141
|
this.client = new SignalClient();
|
@@ -247,7 +247,13 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
247
247
|
});
|
248
248
|
}
|
249
249
|
|
250
|
-
|
250
|
+
/**
|
251
|
+
* Removes sender from PeerConnection, returning true if it was removed successfully
|
252
|
+
* and a negotiation is necessary
|
253
|
+
* @param sender
|
254
|
+
* @returns
|
255
|
+
*/
|
256
|
+
removeTrack(sender: RTCRtpSender): boolean {
|
251
257
|
if (sender.track && this.pendingTrackResolvers[sender.track.id]) {
|
252
258
|
const { reject } = this.pendingTrackResolvers[sender.track.id];
|
253
259
|
if (reject) {
|
@@ -257,9 +263,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
257
263
|
}
|
258
264
|
try {
|
259
265
|
this.publisher?.pc.removeTrack(sender);
|
266
|
+
return true;
|
260
267
|
} catch (e: unknown) {
|
261
268
|
log.warn('failed to remove track', { error: e, method: 'removeTrack' });
|
262
269
|
}
|
270
|
+
return false;
|
263
271
|
}
|
264
272
|
|
265
273
|
updateMuteStatus(trackSid: string, muted: boolean) {
|
@@ -270,8 +278,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
270
278
|
return this.reliableDCSub?.readyState;
|
271
279
|
}
|
272
280
|
|
273
|
-
|
274
|
-
|
281
|
+
async getConnectedServerAddress(): Promise<string | undefined> {
|
282
|
+
if (this.primaryPC === undefined) {
|
283
|
+
return undefined;
|
284
|
+
}
|
285
|
+
return getConnectedAddress(this.primaryPC);
|
275
286
|
}
|
276
287
|
|
277
288
|
private configure(joinResponse: JoinResponse) {
|
@@ -317,11 +328,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
317
328
|
primaryPC.onconnectionstatechange = async () => {
|
318
329
|
log.debug(`primary PC state changed ${primaryPC.connectionState}`);
|
319
330
|
if (primaryPC.connectionState === 'connected') {
|
320
|
-
try {
|
321
|
-
this.connectedServerAddr = await getConnectedAddress(primaryPC);
|
322
|
-
} catch (e) {
|
323
|
-
log.warn('could not get connected server address', { error: e });
|
324
|
-
}
|
325
331
|
const shouldEmit = this.pcState === PCState.New;
|
326
332
|
this.pcState = PCState.Connected;
|
327
333
|
if (shouldEmit) {
|
@@ -334,10 +340,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
334
340
|
|
335
341
|
this.handleDisconnect(
|
336
342
|
'primary peerconnection',
|
337
|
-
false,
|
338
343
|
subscriberPrimary
|
339
|
-
? ReconnectReason.
|
340
|
-
: ReconnectReason.
|
344
|
+
? ReconnectReason.RR_SUBSCRIBER_FAILED
|
345
|
+
: ReconnectReason.RR_PUBLISHER_FAILED,
|
341
346
|
);
|
342
347
|
}
|
343
348
|
}
|
@@ -348,10 +353,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
348
353
|
if (secondaryPC.connectionState === 'failed') {
|
349
354
|
this.handleDisconnect(
|
350
355
|
'secondary peerconnection',
|
351
|
-
false,
|
352
356
|
subscriberPrimary
|
353
|
-
? ReconnectReason.
|
354
|
-
: ReconnectReason.
|
357
|
+
? ReconnectReason.RR_PUBLISHER_FAILED
|
358
|
+
: ReconnectReason.RR_SUBSCRIBER_FAILED,
|
355
359
|
);
|
356
360
|
}
|
357
361
|
};
|
@@ -419,7 +423,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
419
423
|
};
|
420
424
|
|
421
425
|
this.client.onClose = () => {
|
422
|
-
this.handleDisconnect('signal',
|
426
|
+
this.handleDisconnect('signal', ReconnectReason.RR_SIGNAL_DISCONNECTED);
|
423
427
|
};
|
424
428
|
|
425
429
|
this.client.onLeave = (leave?: LeaveRequest) => {
|
@@ -690,11 +694,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
690
694
|
// websocket reconnect behavior. if websocket is interrupted, and the PeerConnection
|
691
695
|
// continues to work, we can reconnect to websocket to continue the session
|
692
696
|
// after a number of retries, we'll close and give up permanently
|
693
|
-
private handleDisconnect = (
|
694
|
-
connection: string,
|
695
|
-
signalEvents: boolean = false,
|
696
|
-
disconnectReason?: ReconnectReason,
|
697
|
-
) => {
|
697
|
+
private handleDisconnect = (connection: string, disconnectReason?: ReconnectReason) => {
|
698
698
|
if (this._isClosed) {
|
699
699
|
return;
|
700
700
|
}
|
@@ -731,12 +731,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
731
731
|
|
732
732
|
this.clearReconnectTimeout();
|
733
733
|
this.reconnectTimeout = CriticalTimers.setTimeout(
|
734
|
-
() => this.attemptReconnect(
|
734
|
+
() => this.attemptReconnect(disconnectReason),
|
735
735
|
delay,
|
736
736
|
);
|
737
737
|
};
|
738
738
|
|
739
|
-
private async attemptReconnect(
|
739
|
+
private async attemptReconnect(reason?: ReconnectReason) {
|
740
740
|
if (this._isClosed) {
|
741
741
|
return;
|
742
742
|
}
|
@@ -756,35 +756,26 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
756
756
|
try {
|
757
757
|
this.attemptingReconnect = true;
|
758
758
|
if (this.fullReconnectOnNext) {
|
759
|
-
await this.restartConnection(
|
759
|
+
await this.restartConnection();
|
760
760
|
} else {
|
761
|
-
await this.resumeConnection(
|
761
|
+
await this.resumeConnection(reason);
|
762
762
|
}
|
763
763
|
this.clearPendingReconnect();
|
764
764
|
this.fullReconnectOnNext = false;
|
765
765
|
} catch (e) {
|
766
766
|
this.reconnectAttempts += 1;
|
767
|
-
let reconnectRequired = false;
|
768
767
|
let recoverable = true;
|
769
|
-
let requireSignalEvents = false;
|
770
768
|
if (e instanceof UnexpectedConnectionState) {
|
771
769
|
log.debug('received unrecoverable error', { error: e });
|
772
770
|
// unrecoverable
|
773
771
|
recoverable = false;
|
774
772
|
} else if (!(e instanceof SignalReconnectError)) {
|
775
773
|
// cannot resume
|
776
|
-
reconnectRequired = true;
|
777
|
-
}
|
778
|
-
|
779
|
-
// when we flip from resume to reconnect
|
780
|
-
// we need to fire the right reconnecting events
|
781
|
-
if (reconnectRequired && !this.fullReconnectOnNext) {
|
782
774
|
this.fullReconnectOnNext = true;
|
783
|
-
requireSignalEvents = true;
|
784
775
|
}
|
785
776
|
|
786
777
|
if (recoverable) {
|
787
|
-
this.handleDisconnect('reconnect',
|
778
|
+
this.handleDisconnect('reconnect', ReconnectReason.RR_UNKOWN);
|
788
779
|
} else {
|
789
780
|
log.info(
|
790
781
|
`could not recover connection after ${this.reconnectAttempts} attempts, ${
|
@@ -810,16 +801,14 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
810
801
|
return null;
|
811
802
|
}
|
812
803
|
|
813
|
-
private async restartConnection(
|
804
|
+
private async restartConnection() {
|
814
805
|
if (!this.url || !this.token) {
|
815
806
|
// permanent failure, don't attempt reconnection
|
816
807
|
throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
|
817
808
|
}
|
818
809
|
|
819
810
|
log.info(`reconnecting, attempt: ${this.reconnectAttempts}`);
|
820
|
-
|
821
|
-
this.emit(EngineEvent.Restarting);
|
822
|
-
}
|
811
|
+
this.emit(EngineEvent.Restarting);
|
823
812
|
|
824
813
|
if (this.client.isConnected) {
|
825
814
|
await this.client.sendLeave();
|
@@ -842,6 +831,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
842
831
|
throw new SignalReconnectError();
|
843
832
|
}
|
844
833
|
|
834
|
+
if (this.shouldFailNext) {
|
835
|
+
this.shouldFailNext = false;
|
836
|
+
throw new Error('simulated failure');
|
837
|
+
}
|
838
|
+
|
845
839
|
await this.waitForPCConnected();
|
846
840
|
this.client.setReconnected();
|
847
841
|
|
@@ -849,10 +843,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
849
843
|
this.emit(EngineEvent.Restarted, joinResponse);
|
850
844
|
}
|
851
845
|
|
852
|
-
private async resumeConnection(
|
853
|
-
emitResuming: boolean = false,
|
854
|
-
reason?: ReconnectReason,
|
855
|
-
): Promise<void> {
|
846
|
+
private async resumeConnection(reason?: ReconnectReason): Promise<void> {
|
856
847
|
if (!this.url || !this.token) {
|
857
848
|
// permanent failure, don't attempt reconnection
|
858
849
|
throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
|
@@ -863,9 +854,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
863
854
|
}
|
864
855
|
|
865
856
|
log.info(`resuming signal connection, attempt ${this.reconnectAttempts}`);
|
866
|
-
|
867
|
-
this.emit(EngineEvent.Resuming);
|
868
|
-
}
|
857
|
+
this.emit(EngineEvent.Resuming);
|
869
858
|
|
870
859
|
try {
|
871
860
|
const res = await this.client.reconnect(this.url, this.token, this.participantSid, reason);
|
@@ -883,6 +872,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
883
872
|
}
|
884
873
|
this.emit(EngineEvent.SignalResumed);
|
885
874
|
|
875
|
+
if (this.shouldFailNext) {
|
876
|
+
this.shouldFailNext = false;
|
877
|
+
throw new Error('simulated failure');
|
878
|
+
}
|
879
|
+
|
886
880
|
this.subscriber.restartingIce = true;
|
887
881
|
|
888
882
|
// only restart publisher if it's needed
|
@@ -921,11 +915,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
921
915
|
this.primaryPC?.connectionState === 'connected'
|
922
916
|
) {
|
923
917
|
this.pcState = PCState.Connected;
|
924
|
-
try {
|
925
|
-
this.connectedServerAddr = await getConnectedAddress(this.primaryPC);
|
926
|
-
} catch (e) {
|
927
|
-
log.warn('could not get connected server address', { error: e });
|
928
|
-
}
|
929
918
|
}
|
930
919
|
if (this.pcState === PCState.Connected) {
|
931
920
|
return;
|
@@ -1022,7 +1011,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1022
1011
|
|
1023
1012
|
const negotiationTimeout = setTimeout(() => {
|
1024
1013
|
reject('negotiation timed out');
|
1025
|
-
this.handleDisconnect('negotiation',
|
1014
|
+
this.handleDisconnect('negotiation', ReconnectReason.RR_SIGNAL_DISCONNECTED);
|
1026
1015
|
}, this.peerConnectionTimeout);
|
1027
1016
|
|
1028
1017
|
const cleanup = () => {
|
@@ -1043,7 +1032,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1043
1032
|
if (e instanceof NegotiationError) {
|
1044
1033
|
this.fullReconnectOnNext = true;
|
1045
1034
|
}
|
1046
|
-
this.handleDisconnect('negotiation',
|
1035
|
+
this.handleDisconnect('negotiation', ReconnectReason.RR_UNKOWN);
|
1047
1036
|
});
|
1048
1037
|
});
|
1049
1038
|
}
|
@@ -1066,6 +1055,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1066
1055
|
}
|
1067
1056
|
}
|
1068
1057
|
|
1058
|
+
/* @internal */
|
1059
|
+
failNext() {
|
1060
|
+
// debugging method to fail the next reconnect/resume attempt
|
1061
|
+
this.shouldFailNext = true;
|
1062
|
+
}
|
1063
|
+
|
1069
1064
|
private clearReconnectTimeout() {
|
1070
1065
|
if (this.reconnectTimeout) {
|
1071
1066
|
CriticalTimers.clearTimeout(this.reconnectTimeout);
|
@@ -1081,7 +1076,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1081
1076
|
// in case the engine is currently reconnecting, attempt a reconnect immediately after the browser state has changed to 'onLine'
|
1082
1077
|
if (this.client.isReconnecting) {
|
1083
1078
|
this.clearReconnectTimeout();
|
1084
|
-
this.attemptReconnect(
|
1079
|
+
this.attemptReconnect(ReconnectReason.RR_SIGNAL_DISCONNECTED);
|
1085
1080
|
}
|
1086
1081
|
};
|
1087
1082
|
|
package/src/room/Room.ts
CHANGED
@@ -56,8 +56,8 @@ import type { AdaptiveStreamSettings } from './track/types';
|
|
56
56
|
import { getNewAudioContext } from './track/utils';
|
57
57
|
import type { SimulationOptions } from './types';
|
58
58
|
import {
|
59
|
-
Future,
|
60
59
|
createDummyVideoStreamTrack,
|
60
|
+
Future,
|
61
61
|
getEmptyAudioStreamTrack,
|
62
62
|
isWeb,
|
63
63
|
Mutex,
|
@@ -516,6 +516,13 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
516
516
|
},
|
517
517
|
});
|
518
518
|
break;
|
519
|
+
case 'resume-reconnect':
|
520
|
+
this.engine.failNext();
|
521
|
+
await this.engine.client.close();
|
522
|
+
if (this.engine.client.onClose) {
|
523
|
+
this.engine.client.onClose('simulate resume-reconnect');
|
524
|
+
}
|
525
|
+
break;
|
519
526
|
case 'force-tcp':
|
520
527
|
case 'force-tls':
|
521
528
|
req = SimulateScenario.fromPartial({
|
@@ -751,45 +758,53 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
751
758
|
log.debug(`reconnected to server`, {
|
752
759
|
region: joinResponse.serverRegion,
|
753
760
|
});
|
754
|
-
this.setAndEmitConnectionState(ConnectionState.Connected);
|
755
|
-
this.emit(RoomEvent.Reconnected);
|
756
761
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
this.handleParticipantUpdates(joinResponse.otherParticipants);
|
764
|
-
|
765
|
-
// unpublish & republish tracks
|
766
|
-
const localPubs: LocalTrackPublication[] = [];
|
767
|
-
this.localParticipant.tracks.forEach((pub) => {
|
768
|
-
if (pub.track) {
|
769
|
-
localPubs.push(pub);
|
762
|
+
try {
|
763
|
+
// rehydrate participants
|
764
|
+
if (joinResponse.participant) {
|
765
|
+
// with a restart, the sid will have changed, we'll map our understanding to it
|
766
|
+
this.localParticipant.sid = joinResponse.participant.sid;
|
767
|
+
this.handleParticipantUpdates([joinResponse.participant]);
|
770
768
|
}
|
771
|
-
|
769
|
+
this.handleParticipantUpdates(joinResponse.otherParticipants);
|
772
770
|
|
773
|
-
|
774
|
-
localPubs
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
771
|
+
// unpublish & republish tracks
|
772
|
+
const localPubs: LocalTrackPublication[] = [];
|
773
|
+
this.localParticipant.tracks.forEach((pub) => {
|
774
|
+
if (pub.track) {
|
775
|
+
localPubs.push(pub);
|
776
|
+
}
|
777
|
+
});
|
778
|
+
|
779
|
+
await Promise.all(
|
780
|
+
localPubs.map(async (pub) => {
|
781
|
+
const track = pub.track!;
|
782
|
+
this.localParticipant.unpublishTrack(track, false);
|
783
|
+
if (!track.isMuted) {
|
784
|
+
if (
|
785
|
+
(track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) &&
|
786
|
+
!track.isUserProvided
|
787
|
+
) {
|
788
|
+
// we need to restart the track before publishing, often a full reconnect
|
789
|
+
// is necessary because computer had gone to sleep.
|
790
|
+
log.debug('restarting existing track', {
|
791
|
+
track: pub.trackSid,
|
792
|
+
});
|
793
|
+
await track.restartTrack();
|
794
|
+
}
|
795
|
+
log.debug('publishing new track', {
|
785
796
|
track: pub.trackSid,
|
786
797
|
});
|
787
|
-
await track.
|
798
|
+
await this.localParticipant.publishTrack(track, pub.options);
|
788
799
|
}
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
800
|
+
}),
|
801
|
+
);
|
802
|
+
} catch (error) {
|
803
|
+
log.error('error trying to re-publish tracks after reconnection', { error });
|
804
|
+
} finally {
|
805
|
+
this.setAndEmitConnectionState(ConnectionState.Connected);
|
806
|
+
this.emit(RoomEvent.Reconnected);
|
807
|
+
}
|
793
808
|
};
|
794
809
|
|
795
810
|
private handleDisconnect(shouldStopTracks = true, reason?: DisconnectReason) {
|
@@ -862,15 +877,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
862
877
|
let remoteParticipant = this.participants.get(info.sid);
|
863
878
|
const isNewParticipant = !remoteParticipant;
|
864
879
|
|
865
|
-
// create participant if doesn't exist
|
866
|
-
remoteParticipant = this.getOrCreateParticipant(info.sid, info);
|
867
|
-
|
868
880
|
// when it's disconnected, send updates
|
869
881
|
if (info.state === ParticipantInfo_State.DISCONNECTED) {
|
870
882
|
this.handleParticipantDisconnected(info.sid, remoteParticipant);
|
871
|
-
} else
|
872
|
-
//
|
873
|
-
remoteParticipant.
|
883
|
+
} else {
|
884
|
+
// create participant if doesn't exist
|
885
|
+
remoteParticipant = this.getOrCreateParticipant(info.sid, info);
|
886
|
+
if (!isNewParticipant) {
|
887
|
+
// just update, no events
|
888
|
+
remoteParticipant.updateInfo(info);
|
889
|
+
}
|
874
890
|
}
|
875
891
|
});
|
876
892
|
};
|
@@ -886,7 +902,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
886
902
|
participant.tracks.forEach((publication) => {
|
887
903
|
participant.unpublishTrack(publication.trackSid, true);
|
888
904
|
});
|
889
|
-
this.
|
905
|
+
this.emit(RoomEvent.ParticipantDisconnected, participant);
|
890
906
|
}
|
891
907
|
|
892
908
|
// updates are sent only when there's a change to speaker ordering
|
@@ -991,7 +1007,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
991
1007
|
// find the participant
|
992
1008
|
const participant = this.participants.get(userPacket.participantSid);
|
993
1009
|
|
994
|
-
this.emit(RoomEvent.DataReceived, userPacket.payload, participant, kind);
|
1010
|
+
this.emit(RoomEvent.DataReceived, userPacket.payload, participant, kind, userPacket.topic);
|
995
1011
|
|
996
1012
|
// also emit on the participant
|
997
1013
|
participant?.emit(ParticipantEvent.DataReceived, userPacket.payload, kind);
|
@@ -1114,7 +1130,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1114
1130
|
},
|
1115
1131
|
)
|
1116
1132
|
.on(ParticipantEvent.TrackUnpublished, (publication: RemoteTrackPublication) => {
|
1117
|
-
this.
|
1133
|
+
this.emit(RoomEvent.TrackUnpublished, publication, participant);
|
1118
1134
|
})
|
1119
1135
|
.on(
|
1120
1136
|
ParticipantEvent.TrackUnsubscribed,
|
@@ -1452,6 +1468,7 @@ export type RoomEventCallbacks = {
|
|
1452
1468
|
payload: Uint8Array,
|
1453
1469
|
participant?: RemoteParticipant,
|
1454
1470
|
kind?: DataPacket_Kind,
|
1471
|
+
topic?: string,
|
1455
1472
|
) => void;
|
1456
1473
|
connectionQualityChanged: (quality: ConnectionQuality, participant: Participant) => void;
|
1457
1474
|
mediaDevicesError: (error: Error) => void;
|
package/src/room/events.ts
CHANGED
@@ -175,7 +175,7 @@ export enum RoomEvent {
|
|
175
175
|
* Data packets provides the ability to use LiveKit to send/receive arbitrary payloads.
|
176
176
|
* All participants in the room will receive the messages sent to the room.
|
177
177
|
*
|
178
|
-
* args: (payload: Uint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]])
|
178
|
+
* args: (payload: Uint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]], topic?: string)
|
179
179
|
*/
|
180
180
|
DataReceived = 'dataReceived',
|
181
181
|
|