livekit-client 0.16.5 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/RequestQueue.js +6 -6
- package/dist/api/RequestQueue.js.map +1 -1
- package/dist/api/SignalClient.d.ts +3 -0
- package/dist/api/SignalClient.js +24 -3
- package/dist/api/SignalClient.js.map +1 -1
- package/dist/connect.js +1 -1
- package/dist/connect.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +7 -2
- package/dist/proto/livekit_models.d.ts +33 -0
- package/dist/proto/livekit_models.js +213 -3
- package/dist/proto/livekit_models.js.map +1 -1
- package/dist/proto/livekit_rtc.d.ts +15 -1
- package/dist/proto/livekit_rtc.js +128 -2
- package/dist/proto/livekit_rtc.js.map +1 -1
- package/dist/room/RTCEngine.d.ts +21 -6
- package/dist/room/RTCEngine.js +13 -8
- package/dist/room/RTCEngine.js.map +1 -1
- package/dist/room/Room.d.ts +43 -6
- package/dist/room/Room.js +81 -59
- package/dist/room/Room.js.map +1 -1
- package/dist/room/events.d.ts +14 -2
- package/dist/room/events.js +16 -4
- package/dist/room/events.js.map +1 -1
- package/dist/room/participant/LocalParticipant.d.ts +3 -1
- package/dist/room/participant/LocalParticipant.js +17 -1
- package/dist/room/participant/LocalParticipant.js.map +1 -1
- package/dist/room/participant/Participant.d.ts +30 -4
- package/dist/room/participant/Participant.js +2 -2
- package/dist/room/participant/Participant.js.map +1 -1
- package/dist/room/participant/RemoteParticipant.d.ts +5 -5
- package/dist/room/participant/RemoteParticipant.js +3 -3
- package/dist/room/participant/RemoteParticipant.js.map +1 -1
- package/dist/room/participant/publishUtils.d.ts +6 -0
- package/dist/room/participant/publishUtils.js +65 -24
- package/dist/room/participant/publishUtils.js.map +1 -1
- package/dist/room/participant/publishUtils.test.js +35 -5
- package/dist/room/participant/publishUtils.test.js.map +1 -1
- package/dist/room/track/LocalAudioTrack.d.ts +2 -0
- package/dist/room/track/LocalAudioTrack.js +23 -0
- package/dist/room/track/LocalAudioTrack.js.map +1 -1
- package/dist/room/track/LocalTrack.d.ts +4 -0
- package/dist/room/track/LocalTrack.js +34 -0
- package/dist/room/track/LocalTrack.js.map +1 -1
- package/dist/room/track/LocalVideoTrack.d.ts +1 -0
- package/dist/room/track/LocalVideoTrack.js +13 -0
- package/dist/room/track/LocalVideoTrack.js.map +1 -1
- package/dist/room/track/RemoteTrack.d.ts +1 -0
- package/dist/room/track/RemoteTrack.js +1 -0
- package/dist/room/track/RemoteTrack.js.map +1 -1
- package/dist/room/track/RemoteVideoTrack.d.ts +4 -2
- package/dist/room/track/RemoteVideoTrack.js +23 -8
- package/dist/room/track/RemoteVideoTrack.js.map +1 -1
- package/dist/room/track/Track.d.ts +20 -4
- package/dist/room/track/Track.js +20 -1
- package/dist/room/track/Track.js.map +1 -1
- package/dist/room/track/defaults.js +2 -2
- package/dist/room/track/defaults.js.map +1 -1
- package/dist/room/track/options.d.ts +65 -15
- package/dist/room/track/options.js +38 -0
- package/dist/room/track/options.js.map +1 -1
- package/dist/room/track/types.d.ts +15 -4
- package/dist/room/track/utils.d.ts +10 -0
- package/dist/room/track/utils.js +46 -1
- package/dist/room/track/utils.js.map +1 -1
- package/dist/room/utils.d.ts +1 -0
- package/dist/room/utils.js +5 -1
- package/dist/room/utils.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
- package/src/api/RequestQueue.ts +7 -7
- package/src/api/SignalClient.ts +31 -4
- package/src/connect.ts +1 -1
- package/src/index.ts +1 -1
- package/src/options.ts +12 -3
- package/src/proto/livekit_models.ts +249 -0
- package/src/proto/livekit_rtc.ts +155 -0
- package/src/room/RTCEngine.ts +43 -11
- package/src/room/Room.ts +152 -66
- package/src/room/events.ts +16 -2
- package/src/room/participant/LocalParticipant.ts +23 -4
- package/src/room/participant/Participant.ts +39 -4
- package/src/room/participant/RemoteParticipant.ts +10 -8
- package/src/room/participant/publishUtils.test.ts +46 -6
- package/src/room/participant/publishUtils.ts +72 -27
- package/src/room/track/LocalAudioTrack.ts +19 -1
- package/src/room/track/LocalTrack.ts +36 -0
- package/src/room/track/LocalVideoTrack.ts +9 -1
- package/src/room/track/RemoteTrack.ts +2 -0
- package/src/room/track/RemoteVideoTrack.ts +22 -9
- package/src/room/track/Track.ts +29 -3
- package/src/room/track/defaults.ts +2 -2
- package/src/room/track/options.ts +55 -3
- package/src/room/track/types.ts +16 -4
- package/src/room/track/utils.ts +39 -0
- package/src/room/utils.ts +4 -0
- package/src/version.ts +1 -1
package/src/room/RTCEngine.ts
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
import { EventEmitter } from 'events';
|
2
|
+
import type TypedEventEmitter from 'typed-emitter';
|
2
3
|
import { SignalClient, SignalOptions } from '../api/SignalClient';
|
3
4
|
import log from '../logger';
|
4
|
-
import {
|
5
|
+
import {
|
6
|
+
ClientConfigSetting,
|
7
|
+
ClientConfiguration,
|
8
|
+
DataPacket, DataPacket_Kind, SpeakerInfo, TrackInfo, UserPacket,
|
9
|
+
} from '../proto/livekit_models';
|
5
10
|
import {
|
6
11
|
AddTrackRequest, JoinResponse,
|
7
12
|
LeaveRequest,
|
@@ -21,7 +26,9 @@ const maxReconnectDuration = 60 * 1000;
|
|
21
26
|
export const maxICEConnectTimeout = 15 * 1000;
|
22
27
|
|
23
28
|
/** @internal */
|
24
|
-
export default class RTCEngine extends
|
29
|
+
export default class RTCEngine extends (
|
30
|
+
EventEmitter as new () => TypedEventEmitter<EngineEventCallbacks>
|
31
|
+
) {
|
25
32
|
publisher?: PCTransport;
|
26
33
|
|
27
34
|
subscriber?: PCTransport;
|
@@ -65,7 +72,9 @@ export default class RTCEngine extends EventEmitter {
|
|
65
72
|
|
66
73
|
private reconnectStart: number = 0;
|
67
74
|
|
68
|
-
private
|
75
|
+
private fullReconnectOnNext: boolean = false;
|
76
|
+
|
77
|
+
private clientConfiguration?: ClientConfiguration;
|
69
78
|
|
70
79
|
private connectedServerAddr?: string;
|
71
80
|
|
@@ -91,6 +100,7 @@ export default class RTCEngine extends EventEmitter {
|
|
91
100
|
if (!this.subscriberPrimary) {
|
92
101
|
this.negotiate();
|
93
102
|
}
|
103
|
+
this.clientConfiguration = joinResponse.clientConfiguration;
|
94
104
|
|
95
105
|
return joinResponse;
|
96
106
|
}
|
@@ -164,6 +174,8 @@ export default class RTCEngine extends EventEmitter {
|
|
164
174
|
this.publisher = new PCTransport(this.rtcConfig);
|
165
175
|
this.subscriber = new PCTransport(this.rtcConfig);
|
166
176
|
|
177
|
+
this.emit(EngineEvent.TransportsCreated, this.publisher, this.subscriber);
|
178
|
+
|
167
179
|
this.publisher.pc.onicecandidate = (ev) => {
|
168
180
|
if (!ev.candidate) return;
|
169
181
|
log.trace('adding ICE candidate for peer', ev.candidate);
|
@@ -296,7 +308,7 @@ export default class RTCEngine extends EventEmitter {
|
|
296
308
|
|
297
309
|
this.client.onLeave = (leave?: LeaveRequest) => {
|
298
310
|
if (leave?.canReconnect) {
|
299
|
-
this.
|
311
|
+
this.fullReconnectOnNext = true;
|
300
312
|
this.primaryPC = undefined;
|
301
313
|
} else {
|
302
314
|
this.emit(EngineEvent.Disconnected);
|
@@ -369,19 +381,19 @@ export default class RTCEngine extends EventEmitter {
|
|
369
381
|
if (this.isClosed) {
|
370
382
|
return;
|
371
383
|
}
|
372
|
-
if (isFireFox()
|
373
|
-
|
374
|
-
this.
|
384
|
+
if (isFireFox() // TODO remove once clientConfiguration handles firefox case server side
|
385
|
+
|| this.clientConfiguration?.resumeConnection === ClientConfigSetting.DISABLED) {
|
386
|
+
this.fullReconnectOnNext = true;
|
375
387
|
}
|
376
388
|
|
377
389
|
try {
|
378
|
-
if (this.
|
390
|
+
if (this.fullReconnectOnNext) {
|
379
391
|
await this.restartConnection();
|
380
392
|
} else {
|
381
393
|
await this.resumeConnection();
|
382
394
|
}
|
383
395
|
this.reconnectAttempts = 0;
|
384
|
-
this.
|
396
|
+
this.fullReconnectOnNext = false;
|
385
397
|
} catch (e) {
|
386
398
|
this.reconnectAttempts += 1;
|
387
399
|
let recoverable = true;
|
@@ -391,7 +403,7 @@ export default class RTCEngine extends EventEmitter {
|
|
391
403
|
recoverable = false;
|
392
404
|
} else if (!(e instanceof SignalReconnectError)) {
|
393
405
|
// cannot resume
|
394
|
-
this.
|
406
|
+
this.fullReconnectOnNext = true;
|
395
407
|
}
|
396
408
|
|
397
409
|
const duration = Date.now() - this.reconnectStart;
|
@@ -437,6 +449,7 @@ export default class RTCEngine extends EventEmitter {
|
|
437
449
|
}
|
438
450
|
|
439
451
|
await this.waitForPCConnected();
|
452
|
+
this.client.setReconnected();
|
440
453
|
|
441
454
|
// reconnect success
|
442
455
|
this.emit(EngineEvent.Restarted, joinResponse);
|
@@ -471,6 +484,7 @@ export default class RTCEngine extends EventEmitter {
|
|
471
484
|
}
|
472
485
|
|
473
486
|
await this.waitForPCConnected();
|
487
|
+
this.client.setReconnected();
|
474
488
|
|
475
489
|
// resume success
|
476
490
|
this.emit(EngineEvent.Resumed);
|
@@ -557,7 +571,7 @@ export default class RTCEngine extends EventEmitter {
|
|
557
571
|
this.publisher.negotiate();
|
558
572
|
}
|
559
573
|
|
560
|
-
|
574
|
+
dataChannelForKind(kind: DataPacket_Kind): RTCDataChannel | undefined {
|
561
575
|
if (kind === DataPacket_Kind.LOSSY) {
|
562
576
|
return this.lossyDC;
|
563
577
|
} if (kind === DataPacket_Kind.RELIABLE) {
|
@@ -602,3 +616,21 @@ async function getConnectedAddress(pc: RTCPeerConnection): Promise<string | unde
|
|
602
616
|
|
603
617
|
class SignalReconnectError extends Error {
|
604
618
|
}
|
619
|
+
|
620
|
+
export type EngineEventCallbacks = {
|
621
|
+
connected: () => void,
|
622
|
+
disconnected: () => void,
|
623
|
+
resuming: () => void,
|
624
|
+
resumed: () => void,
|
625
|
+
restarting: () => void,
|
626
|
+
restarted: (joinResp: JoinResponse) => void,
|
627
|
+
signalResumed: () => void,
|
628
|
+
mediaTrackAdded: (
|
629
|
+
track: MediaStreamTrack,
|
630
|
+
streams: MediaStream,
|
631
|
+
receiver: RTCRtpReceiver
|
632
|
+
) => void,
|
633
|
+
activeSpeakersUpdate: (speakers: Array<SpeakerInfo>) => void,
|
634
|
+
dataPacketReceived: (userPacket: UserPacket, kind: DataPacket_Kind) => void,
|
635
|
+
transportsCreated: (publisher: PCTransport, subscriber: PCTransport) => void,
|
636
|
+
};
|
package/src/room/Room.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { EventEmitter } from 'events';
|
2
|
+
import type TypedEmitter from 'typed-emitter';
|
2
3
|
import { toProtoSessionDescription } from '../api/SignalClient';
|
3
4
|
import log from '../logger';
|
4
5
|
import { RoomConnectOptions, RoomOptions } from '../options';
|
@@ -27,7 +28,8 @@ import LocalTrackPublication from './track/LocalTrackPublication';
|
|
27
28
|
import RemoteTrackPublication from './track/RemoteTrackPublication';
|
28
29
|
import { Track } from './track/Track';
|
29
30
|
import { TrackPublication } from './track/TrackPublication';
|
30
|
-
import { RemoteTrack } from './track/types';
|
31
|
+
import { AdaptiveStreamSettings, RemoteTrack } from './track/types';
|
32
|
+
import { getNewAudioContext } from './track/utils';
|
31
33
|
import { unpackStreamId } from './utils';
|
32
34
|
|
33
35
|
export enum RoomState {
|
@@ -44,7 +46,7 @@ export enum RoomState {
|
|
44
46
|
*
|
45
47
|
* @noInheritDoc
|
46
48
|
*/
|
47
|
-
class Room extends EventEmitter {
|
49
|
+
class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>) {
|
48
50
|
state: RoomState = RoomState.Disconnected;
|
49
51
|
|
50
52
|
/** map of sid: [[RemoteParticipant]] */
|
@@ -145,10 +147,12 @@ class Room extends EventEmitter {
|
|
145
147
|
.on(EngineEvent.Resuming, () => {
|
146
148
|
this.state = RoomState.Reconnecting;
|
147
149
|
this.emit(RoomEvent.Reconnecting);
|
150
|
+
this.emit(RoomEvent.StateChanged, this.state);
|
148
151
|
})
|
149
152
|
.on(EngineEvent.Resumed, () => {
|
150
153
|
this.state = RoomState.Connected;
|
151
154
|
this.emit(RoomEvent.Reconnected);
|
155
|
+
this.emit(RoomEvent.StateChanged, this.state);
|
152
156
|
this.updateSubscriptions();
|
153
157
|
})
|
154
158
|
.on(EngineEvent.SignalResumed, () => {
|
@@ -192,7 +196,7 @@ class Room extends EventEmitter {
|
|
192
196
|
|
193
197
|
try {
|
194
198
|
const joinResponse = await this.engine.join(url, token, opts);
|
195
|
-
log.debug(
|
199
|
+
log.debug(`connected to Livekit Server version: ${joinResponse.serverVersion}, region: ${joinResponse.serverRegion}`);
|
196
200
|
|
197
201
|
if (!joinResponse.serverVersion) {
|
198
202
|
throw new UnsupportedServer('unknown server version');
|
@@ -205,6 +209,7 @@ class Room extends EventEmitter {
|
|
205
209
|
}
|
206
210
|
|
207
211
|
this.state = RoomState.Connected;
|
212
|
+
this.emit(RoomEvent.StateChanged, this.state);
|
208
213
|
const pi = joinResponse.participant!;
|
209
214
|
this.localParticipant = new LocalParticipant(
|
210
215
|
pi.sid,
|
@@ -216,10 +221,10 @@ class Room extends EventEmitter {
|
|
216
221
|
this.localParticipant.updateInfo(pi);
|
217
222
|
// forward metadata changed for the local participant
|
218
223
|
this.localParticipant
|
219
|
-
.on(ParticipantEvent.MetadataChanged, (metadata:
|
224
|
+
.on(ParticipantEvent.MetadataChanged, (metadata: string | undefined) => {
|
220
225
|
this.emit(RoomEvent.MetadataChanged, metadata, this.localParticipant);
|
221
226
|
})
|
222
|
-
.on(ParticipantEvent.ParticipantMetadataChanged, (metadata:
|
227
|
+
.on(ParticipantEvent.ParticipantMetadataChanged, (metadata: string | undefined) => {
|
223
228
|
this.emit(RoomEvent.ParticipantMetadataChanged, metadata, this.localParticipant);
|
224
229
|
})
|
225
230
|
.on(ParticipantEvent.TrackMuted, (pub: TrackPublication) => {
|
@@ -433,18 +438,27 @@ class Room extends EventEmitter {
|
|
433
438
|
if (!trackId || trackId === '') trackId = mediaTrack.id;
|
434
439
|
|
435
440
|
const participant = this.getOrCreateParticipant(participantId);
|
441
|
+
let adaptiveStreamSettings: AdaptiveStreamSettings | undefined;
|
442
|
+
if (this.options.adaptiveStream) {
|
443
|
+
if (typeof this.options.adaptiveStream === 'object') {
|
444
|
+
adaptiveStreamSettings = this.options.adaptiveStream;
|
445
|
+
} else {
|
446
|
+
adaptiveStreamSettings = {};
|
447
|
+
}
|
448
|
+
}
|
436
449
|
participant.addSubscribedMediaTrack(
|
437
450
|
mediaTrack,
|
438
451
|
trackId,
|
439
452
|
stream,
|
440
453
|
receiver,
|
441
|
-
|
454
|
+
adaptiveStreamSettings,
|
442
455
|
);
|
443
456
|
}
|
444
457
|
|
445
458
|
private handleRestarting = () => {
|
446
459
|
this.state = RoomState.Reconnecting;
|
447
460
|
this.emit(RoomEvent.Reconnecting);
|
461
|
+
this.emit(RoomEvent.StateChanged, this.state);
|
448
462
|
|
449
463
|
// also unwind existing participants & existing subscriptions
|
450
464
|
for (const p of this.participants.values()) {
|
@@ -453,8 +467,10 @@ class Room extends EventEmitter {
|
|
453
467
|
};
|
454
468
|
|
455
469
|
private handleRestarted = async (joinResponse: JoinResponse) => {
|
470
|
+
log.debug('reconnected to server region', joinResponse.serverRegion);
|
456
471
|
this.state = RoomState.Connected;
|
457
472
|
this.emit(RoomEvent.Reconnected);
|
473
|
+
this.emit(RoomEvent.StateChanged, this.state);
|
458
474
|
|
459
475
|
// rehydrate participants
|
460
476
|
if (joinResponse.participant) {
|
@@ -509,6 +525,7 @@ class Room extends EventEmitter {
|
|
509
525
|
navigator.mediaDevices.removeEventListener('devicechange', this.handleDeviceChange);
|
510
526
|
this.state = RoomState.Disconnected;
|
511
527
|
this.emit(RoomEvent.Disconnected);
|
528
|
+
this.emit(RoomEvent.StateChanged, this.state);
|
512
529
|
}
|
513
530
|
|
514
531
|
private handleParticipantUpdates = (participantInfos: ParticipantInfo[]) => {
|
@@ -710,73 +727,78 @@ class Room extends EventEmitter {
|
|
710
727
|
}
|
711
728
|
// by using an AudioContext, it reduces lag on audio elements
|
712
729
|
// https://stackoverflow.com/questions/9811429/html5-audio-tag-on-safari-has-a-delay/54119854#54119854
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
this.audioContext = new AudioContext();
|
730
|
+
const ctx = getNewAudioContext();
|
731
|
+
if (ctx) {
|
732
|
+
this.audioContext = ctx;
|
717
733
|
}
|
718
734
|
}
|
719
735
|
|
736
|
+
private createParticipant(id: string, info?: ParticipantInfo): RemoteParticipant {
|
737
|
+
let participant: RemoteParticipant;
|
738
|
+
if (info) {
|
739
|
+
participant = RemoteParticipant.fromParticipantInfo(
|
740
|
+
this.engine.client,
|
741
|
+
info,
|
742
|
+
);
|
743
|
+
} else {
|
744
|
+
participant = new RemoteParticipant(this.engine.client, id, '');
|
745
|
+
}
|
746
|
+
return participant;
|
747
|
+
}
|
748
|
+
|
720
749
|
private getOrCreateParticipant(
|
721
750
|
id: string,
|
722
751
|
info?: ParticipantInfo,
|
723
752
|
): RemoteParticipant {
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
(track
|
747
|
-
// monitor playback status
|
748
|
-
if (track.kind === Track.Kind.Audio) {
|
749
|
-
track.on(TrackEvent.AudioPlaybackStarted, this.handleAudioPlaybackStarted);
|
750
|
-
track.on(TrackEvent.AudioPlaybackFailed, this.handleAudioPlaybackFailed);
|
751
|
-
}
|
752
|
-
this.emit(RoomEvent.TrackSubscribed, track, publication, participant);
|
753
|
-
})
|
754
|
-
.on(ParticipantEvent.TrackUnpublished, (publication: RemoteTrackPublication) => {
|
755
|
-
this.emit(RoomEvent.TrackUnpublished, publication, participant);
|
756
|
-
})
|
757
|
-
.on(ParticipantEvent.TrackUnsubscribed,
|
758
|
-
(track: RemoteTrack, publication: RemoteTrackPublication) => {
|
759
|
-
this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
|
760
|
-
})
|
761
|
-
.on(ParticipantEvent.TrackSubscriptionFailed, (sid: string) => {
|
762
|
-
this.emit(RoomEvent.TrackSubscriptionFailed, sid, participant);
|
763
|
-
})
|
764
|
-
.on(ParticipantEvent.TrackMuted, (pub: TrackPublication) => {
|
765
|
-
this.emit(RoomEvent.TrackMuted, pub, participant);
|
766
|
-
})
|
767
|
-
.on(ParticipantEvent.TrackUnmuted, (pub: TrackPublication) => {
|
768
|
-
this.emit(RoomEvent.TrackUnmuted, pub, participant);
|
769
|
-
})
|
770
|
-
.on(ParticipantEvent.MetadataChanged, (metadata: any) => {
|
771
|
-
this.emit(RoomEvent.MetadataChanged, metadata, participant);
|
753
|
+
if (this.participants.has(id)) {
|
754
|
+
return (this.participants.get(id) as RemoteParticipant);
|
755
|
+
}
|
756
|
+
// it's possible for the RTC track to arrive before signaling data
|
757
|
+
// when this happens, we'll create the participant and make the track work
|
758
|
+
const participant = this.createParticipant(id, info);
|
759
|
+
this.participants.set(id, participant);
|
760
|
+
|
761
|
+
// also forward events
|
762
|
+
// trackPublished is only fired for tracks added after both local participant
|
763
|
+
// and remote participant joined the room
|
764
|
+
participant
|
765
|
+
.on(ParticipantEvent.TrackPublished, (trackPublication: RemoteTrackPublication) => {
|
766
|
+
this.emit(RoomEvent.TrackPublished, trackPublication, participant);
|
767
|
+
})
|
768
|
+
.on(ParticipantEvent.TrackSubscribed,
|
769
|
+
(track: RemoteTrack, publication: RemoteTrackPublication) => {
|
770
|
+
// monitor playback status
|
771
|
+
if (track.kind === Track.Kind.Audio) {
|
772
|
+
track.on(TrackEvent.AudioPlaybackStarted, this.handleAudioPlaybackStarted);
|
773
|
+
track.on(TrackEvent.AudioPlaybackFailed, this.handleAudioPlaybackFailed);
|
774
|
+
}
|
775
|
+
this.emit(RoomEvent.TrackSubscribed, track, publication, participant);
|
772
776
|
})
|
773
|
-
|
774
|
-
|
777
|
+
.on(ParticipantEvent.TrackUnpublished, (publication: RemoteTrackPublication) => {
|
778
|
+
this.emit(RoomEvent.TrackUnpublished, publication, participant);
|
779
|
+
})
|
780
|
+
.on(ParticipantEvent.TrackUnsubscribed,
|
781
|
+
(track: RemoteTrack, publication: RemoteTrackPublication) => {
|
782
|
+
this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
|
775
783
|
})
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
784
|
+
.on(ParticipantEvent.TrackSubscriptionFailed, (sid: string) => {
|
785
|
+
this.emit(RoomEvent.TrackSubscriptionFailed, sid, participant);
|
786
|
+
})
|
787
|
+
.on(ParticipantEvent.TrackMuted, (pub: TrackPublication) => {
|
788
|
+
this.emit(RoomEvent.TrackMuted, pub, participant);
|
789
|
+
})
|
790
|
+
.on(ParticipantEvent.TrackUnmuted, (pub: TrackPublication) => {
|
791
|
+
this.emit(RoomEvent.TrackUnmuted, pub, participant);
|
792
|
+
})
|
793
|
+
.on(ParticipantEvent.MetadataChanged, (metadata: string | undefined) => {
|
794
|
+
this.emit(RoomEvent.MetadataChanged, metadata, participant);
|
795
|
+
})
|
796
|
+
.on(ParticipantEvent.ParticipantMetadataChanged, (metadata: string | undefined) => {
|
797
|
+
this.emit(RoomEvent.ParticipantMetadataChanged, metadata, participant);
|
798
|
+
})
|
799
|
+
.on(ParticipantEvent.ConnectionQualityChanged, (quality: ConnectionQuality) => {
|
800
|
+
this.emit(RoomEvent.ConnectionQualityChanged, quality, participant);
|
801
|
+
});
|
780
802
|
return participant;
|
781
803
|
}
|
782
804
|
|
@@ -813,6 +835,7 @@ class Room extends EventEmitter {
|
|
813
835
|
participantTracks: [],
|
814
836
|
},
|
815
837
|
publishTracks: this.localParticipant.publishedTracksInfo(),
|
838
|
+
dataChannels: this.localParticipant.dataChannelsInfo(),
|
816
839
|
});
|
817
840
|
}
|
818
841
|
|
@@ -830,11 +853,74 @@ class Room extends EventEmitter {
|
|
830
853
|
}
|
831
854
|
}
|
832
855
|
|
833
|
-
/** @internal */
|
834
|
-
emit
|
856
|
+
// /** @internal */
|
857
|
+
emit<E extends keyof RoomEventCallbacks>(
|
858
|
+
event: E, ...args: Parameters<RoomEventCallbacks[E]>
|
859
|
+
): boolean {
|
835
860
|
log.debug('room event', event, ...args);
|
836
861
|
return super.emit(event, ...args);
|
837
862
|
}
|
838
863
|
}
|
839
864
|
|
840
865
|
export default Room;
|
866
|
+
|
867
|
+
export type RoomEventCallbacks = {
|
868
|
+
reconnecting: () => void,
|
869
|
+
reconnected: () => void,
|
870
|
+
disconnected: () => void,
|
871
|
+
stateChanged: (state: RoomState) => void,
|
872
|
+
mediaDevicesChanged: () => void,
|
873
|
+
participantConnected: (participant: RemoteParticipant) => void,
|
874
|
+
participantDisconnected: (participant: RemoteParticipant) => void,
|
875
|
+
trackPublished: (publication: RemoteTrackPublication, participant: RemoteParticipant) => void,
|
876
|
+
trackSubscribed: (
|
877
|
+
track: RemoteTrack,
|
878
|
+
publication: RemoteTrackPublication,
|
879
|
+
participant: RemoteParticipant
|
880
|
+
) => void,
|
881
|
+
trackSubscriptionFailed: (trackSid: string, participant: RemoteParticipant) => void,
|
882
|
+
trackUnpublished: (publication: RemoteTrackPublication, participant: RemoteParticipant) => void,
|
883
|
+
trackUnsubscribed: (
|
884
|
+
track: RemoteTrack,
|
885
|
+
publication: RemoteTrackPublication,
|
886
|
+
participant: RemoteParticipant,
|
887
|
+
) => void,
|
888
|
+
trackMuted: (publication: TrackPublication, participant: Participant) => void,
|
889
|
+
trackUnmuted: (publication: TrackPublication, participant: Participant) => void,
|
890
|
+
localTrackPublished: (publication: LocalTrackPublication, participant: LocalParticipant) => void,
|
891
|
+
localTrackUnpublished: (
|
892
|
+
publication: LocalTrackPublication,
|
893
|
+
participant: LocalParticipant
|
894
|
+
) => void,
|
895
|
+
/**
|
896
|
+
* @deprecated use [[participantMetadataChanged]] instead
|
897
|
+
*/
|
898
|
+
metadataChanged: (
|
899
|
+
metadata: string | undefined,
|
900
|
+
participant?: RemoteParticipant | LocalParticipant
|
901
|
+
) => void,
|
902
|
+
participantMetadataChanged: (
|
903
|
+
metadata: string | undefined,
|
904
|
+
participant: RemoteParticipant | LocalParticipant
|
905
|
+
) => void,
|
906
|
+
activeSpeakersChanged: (speakers: Array<Participant>) => void,
|
907
|
+
roomMetadataChanged: (metadata: string) => void,
|
908
|
+
dataReceived: (
|
909
|
+
payload: Uint8Array,
|
910
|
+
participant?: RemoteParticipant,
|
911
|
+
kind?: DataPacket_Kind
|
912
|
+
) => void,
|
913
|
+
connectionQualityChanged: (quality: ConnectionQuality, participant: Participant) => void,
|
914
|
+
mediaDevicesError: (error: Error) => void,
|
915
|
+
trackStreamStateChanged: (
|
916
|
+
publication: RemoteTrackPublication,
|
917
|
+
streamState: Track.StreamState,
|
918
|
+
participant: RemoteParticipant,
|
919
|
+
) => void,
|
920
|
+
trackSubscriptionPermissionChanged: (
|
921
|
+
publication: RemoteTrackPublication,
|
922
|
+
status: TrackPublication.SubscriptionStatus,
|
923
|
+
participant: RemoteParticipant,
|
924
|
+
) => void,
|
925
|
+
audioPlaybackChanged: (playing: boolean) => void,
|
926
|
+
};
|
package/src/room/events.ts
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
* room.on(RoomEvent.TrackPublished, (track, publication, participant) => {})
|
8
8
|
* ```
|
9
9
|
*/
|
10
|
+
|
10
11
|
export enum RoomEvent {
|
11
12
|
/**
|
12
13
|
* When the connection to the server has been interrupted and it's attempting
|
@@ -25,6 +26,13 @@ export enum RoomEvent {
|
|
25
26
|
*/
|
26
27
|
Disconnected = 'disconnected',
|
27
28
|
|
29
|
+
/**
|
30
|
+
* Whenever the connection state of the room changes
|
31
|
+
*
|
32
|
+
* args: ([[RoomState]])
|
33
|
+
*/
|
34
|
+
StateChanged = 'stateChanged',
|
35
|
+
|
28
36
|
/**
|
29
37
|
* When input or output devices on the machine have changed.
|
30
38
|
*/
|
@@ -146,7 +154,7 @@ export enum RoomEvent {
|
|
146
154
|
* args: (prevMetadata: string, [[Participant]])
|
147
155
|
*
|
148
156
|
*/
|
149
|
-
ParticipantMetadataChanged = '
|
157
|
+
ParticipantMetadataChanged = 'participantMetadataChanged',
|
150
158
|
|
151
159
|
/**
|
152
160
|
* Room metadata is a simple way for app-specific state to be pushed to
|
@@ -177,7 +185,7 @@ export enum RoomEvent {
|
|
177
185
|
ConnectionQualityChanged = 'connectionQualityChanged',
|
178
186
|
|
179
187
|
/**
|
180
|
-
* StreamState indicates if a subscribed track has been paused by the SFU
|
188
|
+
* StreamState indicates if a subscribed (remote) track has been paused by the SFU
|
181
189
|
* (typically this happens because of subscriber's bandwidth constraints)
|
182
190
|
*
|
183
191
|
* When bandwidth conditions allow, the track will be resumed automatically.
|
@@ -366,6 +374,7 @@ export enum ParticipantEvent {
|
|
366
374
|
|
367
375
|
/** @internal */
|
368
376
|
export enum EngineEvent {
|
377
|
+
TransportsCreated = 'transportsCreated',
|
369
378
|
Connected = 'connected',
|
370
379
|
Disconnected = 'disconnected',
|
371
380
|
Resuming = 'resuming',
|
@@ -391,6 +400,11 @@ export enum TrackEvent {
|
|
391
400
|
AudioPlaybackStarted = 'audioPlaybackStarted',
|
392
401
|
/** @internal */
|
393
402
|
AudioPlaybackFailed = 'audioPlaybackFailed',
|
403
|
+
/**
|
404
|
+
* @internal
|
405
|
+
* Only fires on LocalAudioTrack instances
|
406
|
+
*/
|
407
|
+
AudioSilenceDetected = 'audioSilenceDetected',
|
394
408
|
/** @internal */
|
395
409
|
VisibilityChanged = 'visibilityChanged',
|
396
410
|
/** @internal */
|
@@ -3,7 +3,9 @@ import { RoomOptions } from '../../options';
|
|
3
3
|
import {
|
4
4
|
DataPacket, DataPacket_Kind,
|
5
5
|
} from '../../proto/livekit_models';
|
6
|
-
import {
|
6
|
+
import {
|
7
|
+
AddTrackRequest, DataChannelInfo, SubscribedQualityUpdate, TrackPublishedResponse,
|
8
|
+
} from '../../proto/livekit_rtc';
|
7
9
|
import {
|
8
10
|
TrackInvalidError,
|
9
11
|
UnexpectedConnectionState,
|
@@ -17,7 +19,8 @@ import LocalVideoTrack, { videoLayersFromEncodings } from '../track/LocalVideoTr
|
|
17
19
|
import {
|
18
20
|
CreateLocalTracksOptions,
|
19
21
|
ScreenShareCaptureOptions,
|
20
|
-
|
22
|
+
ScreenSharePresets,
|
23
|
+
TrackPublishOptions, VideoCodec,
|
21
24
|
} from '../track/options';
|
22
25
|
import { Track } from '../track/Track';
|
23
26
|
import { constraintsForOptions, mergeDefaultOptions } from '../track/utils';
|
@@ -272,7 +275,7 @@ export default class LocalParticipant extends Participant {
|
|
272
275
|
options = {};
|
273
276
|
}
|
274
277
|
if (options.resolution === undefined) {
|
275
|
-
options.resolution =
|
278
|
+
options.resolution = ScreenSharePresets.h1080fps15.resolution;
|
276
279
|
}
|
277
280
|
|
278
281
|
let videoConstraints: MediaTrackConstraints | boolean = true;
|
@@ -525,7 +528,7 @@ export default class LocalParticipant extends Participant {
|
|
525
528
|
destination?: RemoteParticipant[] | string[]) {
|
526
529
|
const dest: string[] = [];
|
527
530
|
if (destination !== undefined) {
|
528
|
-
destination.forEach((val
|
531
|
+
destination.forEach((val: any) => {
|
529
532
|
if (val instanceof RemoteParticipant) {
|
530
533
|
dest.push(val.sid);
|
531
534
|
} else {
|
@@ -681,4 +684,20 @@ export default class LocalParticipant extends Participant {
|
|
681
684
|
});
|
682
685
|
return infos;
|
683
686
|
}
|
687
|
+
|
688
|
+
/** @internal */
|
689
|
+
dataChannelsInfo(): DataChannelInfo[] {
|
690
|
+
const infos: DataChannelInfo[] = [];
|
691
|
+
const getInfo = (dc: RTCDataChannel | undefined) => {
|
692
|
+
if (dc?.id !== undefined && dc.id !== null) {
|
693
|
+
infos.push({
|
694
|
+
label: dc.label,
|
695
|
+
id: dc.id,
|
696
|
+
});
|
697
|
+
}
|
698
|
+
};
|
699
|
+
getInfo(this.engine.dataChannelForKind(DataPacket_Kind.LOSSY));
|
700
|
+
getInfo(this.engine.dataChannelForKind(DataPacket_Kind.RELIABLE));
|
701
|
+
return infos;
|
702
|
+
}
|
684
703
|
}
|
@@ -1,8 +1,12 @@
|
|
1
1
|
import { EventEmitter } from 'events';
|
2
|
-
import
|
2
|
+
import type TypedEmitter from 'typed-emitter';
|
3
|
+
import { ConnectionQuality as ProtoQuality, DataPacket_Kind, ParticipantInfo } from '../../proto/livekit_models';
|
3
4
|
import { ParticipantEvent, TrackEvent } from '../events';
|
5
|
+
import LocalTrackPublication from '../track/LocalTrackPublication';
|
6
|
+
import RemoteTrackPublication from '../track/RemoteTrackPublication';
|
4
7
|
import { Track } from '../track/Track';
|
5
8
|
import { TrackPublication } from '../track/TrackPublication';
|
9
|
+
import { RemoteTrack } from '../track/types';
|
6
10
|
|
7
11
|
export enum ConnectionQuality {
|
8
12
|
Excellent = 'excellent',
|
@@ -24,7 +28,9 @@ function qualityFromProto(q: ProtoQuality): ConnectionQuality {
|
|
24
28
|
}
|
25
29
|
}
|
26
30
|
|
27
|
-
export default class Participant extends
|
31
|
+
export default class Participant extends (
|
32
|
+
EventEmitter as new () => TypedEmitter<ParticipantEventCallbacks>
|
33
|
+
) {
|
28
34
|
protected participantInfo?: ParticipantInfo;
|
29
35
|
|
30
36
|
audioTracks: Map<string, TrackPublication>;
|
@@ -158,8 +164,8 @@ export default class Participant extends EventEmitter {
|
|
158
164
|
this.metadata = md;
|
159
165
|
|
160
166
|
if (changed) {
|
161
|
-
this.emit(ParticipantEvent.MetadataChanged, prevMetadata
|
162
|
-
this.emit(ParticipantEvent.ParticipantMetadataChanged, prevMetadata
|
167
|
+
this.emit(ParticipantEvent.MetadataChanged, prevMetadata);
|
168
|
+
this.emit(ParticipantEvent.ParticipantMetadataChanged, prevMetadata);
|
163
169
|
}
|
164
170
|
}
|
165
171
|
|
@@ -212,3 +218,32 @@ export default class Participant extends EventEmitter {
|
|
212
218
|
}
|
213
219
|
}
|
214
220
|
}
|
221
|
+
|
222
|
+
export type ParticipantEventCallbacks = {
|
223
|
+
trackPublished: (publication: RemoteTrackPublication) => void,
|
224
|
+
trackSubscribed: (track: RemoteTrack, publication: RemoteTrackPublication) => void,
|
225
|
+
trackSubscriptionFailed: (trackSid: string) => void,
|
226
|
+
trackUnpublished: (publication: RemoteTrackPublication) => void,
|
227
|
+
trackUnsubscribed: (track: RemoteTrack, publication: RemoteTrackPublication) => void,
|
228
|
+
trackMuted: (publication: TrackPublication) => void,
|
229
|
+
trackUnmuted: (publication: TrackPublication) => void,
|
230
|
+
localTrackPublished: (publication: LocalTrackPublication) => void,
|
231
|
+
localTrackUnpublished: (publication: LocalTrackPublication) => void,
|
232
|
+
/**
|
233
|
+
* @deprecated use [[participantMetadataChanged]] instead
|
234
|
+
*/
|
235
|
+
metadataChanged: (prevMetadata: string | undefined, participant?: any) => void,
|
236
|
+
participantMetadataChanged: (prevMetadata: string | undefined, participant?: any) => void,
|
237
|
+
dataReceived: (payload: Uint8Array, kind: DataPacket_Kind) => void,
|
238
|
+
isSpeakingChanged: (speaking: boolean) => void,
|
239
|
+
connectionQualityChanged: (connectionQuality: ConnectionQuality) => void,
|
240
|
+
trackStreamStateChanged: (
|
241
|
+
publication: RemoteTrackPublication,
|
242
|
+
streamState: Track.StreamState
|
243
|
+
) => void,
|
244
|
+
trackSubscriptionPermissionChanged: (
|
245
|
+
publication: RemoteTrackPublication,
|
246
|
+
status: TrackPublication.SubscriptionStatus
|
247
|
+
) => void,
|
248
|
+
mediaDevicesError: (error: Error) => void,
|
249
|
+
};
|