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
@@ -29,7 +29,8 @@ import {
|
|
29
29
|
} from '../track/options';
|
30
30
|
import { Track } from '../track/Track';
|
31
31
|
import { constraintsForOptions, mergeDefaultOptions } from '../track/utils';
|
32
|
-
import {
|
32
|
+
import type { DataPublishOptions } from '../types';
|
33
|
+
import { Future, isFireFox, isSafari, isWeb, supportsAV1 } from '../utils';
|
33
34
|
import Participant from './Participant';
|
34
35
|
import { ParticipantTrackPermission, trackPermissionToProto } from './ParticipantTrackPermission';
|
35
36
|
import {
|
@@ -52,6 +53,8 @@ export default class LocalParticipant extends Participant {
|
|
52
53
|
|
53
54
|
private pendingPublishing = new Set<Track.Source>();
|
54
55
|
|
56
|
+
private pendingPublishPromises = new Map<LocalTrack, Promise<LocalTrackPublication>>();
|
57
|
+
|
55
58
|
private cameraError: Error | undefined;
|
56
59
|
|
57
60
|
private microphoneError: Error | undefined;
|
@@ -63,6 +66,8 @@ export default class LocalParticipant extends Participant {
|
|
63
66
|
// keep a pointer to room options
|
64
67
|
private roomOptions: InternalRoomOptions;
|
65
68
|
|
69
|
+
private reconnectFuture?: Future<void>;
|
70
|
+
|
66
71
|
/** @internal */
|
67
72
|
constructor(sid: string, identity: string, engine: RTCEngine, options: InternalRoomOptions) {
|
68
73
|
super(sid, identity);
|
@@ -118,11 +123,25 @@ export default class LocalParticipant extends Participant {
|
|
118
123
|
this.engine.client.onLocalTrackUnpublished = this.handleLocalTrackUnpublished;
|
119
124
|
|
120
125
|
this.engine
|
121
|
-
.on(EngineEvent.Connected, this.
|
122
|
-
.on(EngineEvent.Restarted, this.
|
123
|
-
.on(EngineEvent.Resumed, this.
|
126
|
+
.on(EngineEvent.Connected, this.handleReconnected)
|
127
|
+
.on(EngineEvent.Restarted, this.handleReconnected)
|
128
|
+
.on(EngineEvent.Resumed, this.handleReconnected)
|
129
|
+
.on(EngineEvent.Restarting, this.handleReconnecting)
|
130
|
+
.on(EngineEvent.Resuming, this.handleReconnecting);
|
124
131
|
}
|
125
132
|
|
133
|
+
private handleReconnecting = () => {
|
134
|
+
if (!this.reconnectFuture) {
|
135
|
+
this.reconnectFuture = new Future<void>();
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
private handleReconnected = () => {
|
140
|
+
this.reconnectFuture?.resolve?.();
|
141
|
+
this.reconnectFuture = undefined;
|
142
|
+
this.updateTrackSubscriptionPermissions();
|
143
|
+
};
|
144
|
+
|
126
145
|
/**
|
127
146
|
* Enable or disable a participant's camera track.
|
128
147
|
*
|
@@ -382,6 +401,11 @@ export default class LocalParticipant extends Participant {
|
|
382
401
|
const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
|
383
402
|
audio: options.audio ?? false,
|
384
403
|
video: videoConstraints,
|
404
|
+
// @ts-expect-error support for experimental display media features
|
405
|
+
controller: options.controller,
|
406
|
+
selfBrowserSurface: options.selfBrowserSurface,
|
407
|
+
surfaceSwitching: options.surfaceSwitching,
|
408
|
+
systemAudio: options.systemAudio,
|
385
409
|
});
|
386
410
|
|
387
411
|
const tracks = stream.getVideoTracks();
|
@@ -408,6 +432,10 @@ export default class LocalParticipant extends Participant {
|
|
408
432
|
track: LocalTrack | MediaStreamTrack,
|
409
433
|
options?: TrackPublishOptions,
|
410
434
|
): Promise<LocalTrackPublication> {
|
435
|
+
await this.reconnectFuture?.promise;
|
436
|
+
if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) {
|
437
|
+
await this.pendingPublishPromises.get(track);
|
438
|
+
}
|
411
439
|
// convert raw media track into audio or video track
|
412
440
|
if (track instanceof MediaStreamTrack) {
|
413
441
|
switch (track.kind) {
|
@@ -422,6 +450,22 @@ export default class LocalParticipant extends Participant {
|
|
422
450
|
}
|
423
451
|
}
|
424
452
|
|
453
|
+
// is it already published? if so skip
|
454
|
+
let existingPublication: LocalTrackPublication | undefined;
|
455
|
+
this.tracks.forEach((publication) => {
|
456
|
+
if (!publication.track) {
|
457
|
+
return;
|
458
|
+
}
|
459
|
+
if (publication.track === track) {
|
460
|
+
existingPublication = <LocalTrackPublication>publication;
|
461
|
+
}
|
462
|
+
});
|
463
|
+
|
464
|
+
if (existingPublication) {
|
465
|
+
log.warn('track has already been published, skipping');
|
466
|
+
return existingPublication;
|
467
|
+
}
|
468
|
+
|
425
469
|
const isStereo =
|
426
470
|
options?.forceStereo ||
|
427
471
|
('channelCount' in track.mediaStreamTrack.getSettings() &&
|
@@ -439,29 +483,40 @@ export default class LocalParticipant extends Participant {
|
|
439
483
|
`Opus DTX will be disabled for stereo tracks by default. Enable them explicitly to make it work.`,
|
440
484
|
);
|
441
485
|
}
|
486
|
+
if (options.red === undefined) {
|
487
|
+
log.info(
|
488
|
+
`Opus RED will be disabled for stereo tracks by default. Enable them explicitly to make it work.`,
|
489
|
+
);
|
490
|
+
}
|
442
491
|
options.dtx ??= false;
|
492
|
+
options.red ??= false;
|
443
493
|
}
|
444
494
|
const opts: TrackPublishOptions = {
|
445
495
|
...this.roomOptions.publishDefaults,
|
446
496
|
...options,
|
447
497
|
};
|
448
498
|
|
449
|
-
// is it already published? if so skip
|
450
|
-
let existingPublication: LocalTrackPublication | undefined;
|
451
|
-
this.tracks.forEach((publication) => {
|
452
|
-
if (!publication.track) {
|
453
|
-
return;
|
454
|
-
}
|
455
|
-
if (publication.track === track) {
|
456
|
-
existingPublication = <LocalTrackPublication>publication;
|
457
|
-
}
|
458
|
-
});
|
459
|
-
|
460
|
-
if (existingPublication) return existingPublication;
|
461
|
-
|
462
499
|
if (opts.source) {
|
463
500
|
track.source = opts.source;
|
464
501
|
}
|
502
|
+
const publishPromise = this.publish(track, opts, options, isStereo);
|
503
|
+
this.pendingPublishPromises.set(track, publishPromise);
|
504
|
+
try {
|
505
|
+
const publication = await publishPromise;
|
506
|
+
return publication;
|
507
|
+
} catch (e) {
|
508
|
+
throw e;
|
509
|
+
} finally {
|
510
|
+
this.pendingPublishPromises.delete(track);
|
511
|
+
}
|
512
|
+
}
|
513
|
+
|
514
|
+
private async publish(
|
515
|
+
track: LocalTrack,
|
516
|
+
opts: TrackPublishOptions,
|
517
|
+
options: TrackPublishOptions | undefined,
|
518
|
+
isStereo: boolean,
|
519
|
+
) {
|
465
520
|
const existingTrackOfSource = Array.from(this.tracks.values()).find(
|
466
521
|
(publishedTrack) => track instanceof LocalTrack && publishedTrack.source === track.source,
|
467
522
|
);
|
@@ -721,17 +776,24 @@ export default class LocalParticipant extends Participant {
|
|
721
776
|
track.stop();
|
722
777
|
}
|
723
778
|
|
779
|
+
let negotiationNeeded = false;
|
780
|
+
const trackSender = track.sender;
|
781
|
+
track.sender = undefined;
|
724
782
|
if (
|
725
783
|
this.engine.publisher &&
|
726
784
|
this.engine.publisher.pc.connectionState !== 'closed' &&
|
727
|
-
|
785
|
+
trackSender
|
728
786
|
) {
|
729
787
|
try {
|
730
|
-
this.engine.removeTrack(
|
788
|
+
if (this.engine.removeTrack(trackSender)) {
|
789
|
+
negotiationNeeded = true;
|
790
|
+
}
|
731
791
|
if (track instanceof LocalVideoTrack) {
|
732
792
|
for (const [, trackInfo] of track.simulcastCodecs) {
|
733
793
|
if (trackInfo.sender) {
|
734
|
-
this.engine.removeTrack(trackInfo.sender)
|
794
|
+
if (this.engine.removeTrack(trackInfo.sender)) {
|
795
|
+
negotiationNeeded = true;
|
796
|
+
}
|
735
797
|
trackInfo.sender = undefined;
|
736
798
|
}
|
737
799
|
}
|
@@ -739,13 +801,9 @@ export default class LocalParticipant extends Participant {
|
|
739
801
|
}
|
740
802
|
} catch (e) {
|
741
803
|
log.warn('failed to unpublish track', { error: e, method: 'unpublishTrack' });
|
742
|
-
} finally {
|
743
|
-
await this.engine.negotiate();
|
744
804
|
}
|
745
805
|
}
|
746
806
|
|
747
|
-
track.sender = undefined;
|
748
|
-
|
749
807
|
// remove from our maps
|
750
808
|
this.tracks.delete(publication.trackSid);
|
751
809
|
switch (publication.kind) {
|
@@ -762,6 +820,9 @@ export default class LocalParticipant extends Participant {
|
|
762
820
|
this.emit(ParticipantEvent.LocalTrackUnpublished, publication);
|
763
821
|
publication.setTrack(undefined);
|
764
822
|
|
823
|
+
if (negotiationNeeded) {
|
824
|
+
await this.engine.negotiate();
|
825
|
+
}
|
765
826
|
return publication;
|
766
827
|
}
|
767
828
|
|
@@ -794,6 +855,22 @@ export default class LocalParticipant extends Participant {
|
|
794
855
|
);
|
795
856
|
}
|
796
857
|
|
858
|
+
/**
|
859
|
+
* Publish a new data payload to the room. Data will be forwarded to each
|
860
|
+
* participant in the room if the destination field in publishOptions is empty
|
861
|
+
*
|
862
|
+
* @param data Uint8Array of the payload. To send string data, use TextEncoder.encode
|
863
|
+
* @param kind whether to send this as reliable or lossy.
|
864
|
+
* For data that you need delivery guarantee (such as chat messages), use Reliable.
|
865
|
+
* For data that should arrive as quickly as possible, but you are ok with dropped
|
866
|
+
* packets, use Lossy.
|
867
|
+
* @param publishOptions optionally specify a `topic` and `destination`
|
868
|
+
*/
|
869
|
+
async publishData(
|
870
|
+
data: Uint8Array,
|
871
|
+
kind: DataPacket_Kind,
|
872
|
+
publishOptions?: DataPublishOptions,
|
873
|
+
): Promise<void>;
|
797
874
|
/**
|
798
875
|
* Publish a new data payload to the room. Data will be forwarded to each
|
799
876
|
* participant in the room if the destination argument is empty
|
@@ -809,14 +886,26 @@ export default class LocalParticipant extends Participant {
|
|
809
886
|
data: Uint8Array,
|
810
887
|
kind: DataPacket_Kind,
|
811
888
|
destination?: RemoteParticipant[] | string[],
|
889
|
+
): Promise<void>;
|
890
|
+
|
891
|
+
async publishData(
|
892
|
+
data: Uint8Array,
|
893
|
+
kind: DataPacket_Kind,
|
894
|
+
publishOptions: DataPublishOptions | RemoteParticipant[] | string[] = {},
|
812
895
|
) {
|
813
|
-
const
|
896
|
+
const destination = Array.isArray(publishOptions)
|
897
|
+
? publishOptions
|
898
|
+
: publishOptions?.destination;
|
899
|
+
const destinationSids: string[] = [];
|
900
|
+
|
901
|
+
const topic = !Array.isArray(publishOptions) ? publishOptions.topic : undefined;
|
902
|
+
|
814
903
|
if (destination !== undefined) {
|
815
904
|
destination.forEach((val: any) => {
|
816
905
|
if (val instanceof RemoteParticipant) {
|
817
|
-
|
906
|
+
destinationSids.push(val.sid);
|
818
907
|
} else {
|
819
|
-
|
908
|
+
destinationSids.push(val);
|
820
909
|
}
|
821
910
|
});
|
822
911
|
}
|
@@ -828,7 +917,8 @@ export default class LocalParticipant extends Participant {
|
|
828
917
|
user: {
|
829
918
|
participantSid: this.sid,
|
830
919
|
payload: data,
|
831
|
-
destinationSids:
|
920
|
+
destinationSids: destinationSids,
|
921
|
+
topic,
|
832
922
|
},
|
833
923
|
},
|
834
924
|
};
|
@@ -236,8 +236,7 @@ export default class RemoteParticipant extends Participant {
|
|
236
236
|
}
|
237
237
|
publication = new RemoteTrackPublication(
|
238
238
|
kind,
|
239
|
-
ti
|
240
|
-
ti.name,
|
239
|
+
ti,
|
241
240
|
this.signalClient.connectOptions?.autoSubscribe,
|
242
241
|
);
|
243
242
|
publication.updateInfo(ti);
|
@@ -246,7 +245,7 @@ export default class RemoteParticipant extends Participant {
|
|
246
245
|
(publishedTrack) => publishedTrack.source === publication?.source,
|
247
246
|
);
|
248
247
|
if (existingTrackOfSource && publication.source !== Track.Source.Unknown) {
|
249
|
-
log.
|
248
|
+
log.debug(
|
250
249
|
`received a second track publication for ${this.identity} with the same source: ${publication.source}`,
|
251
250
|
{
|
252
251
|
oldTrack: existingTrackOfSource,
|
@@ -24,9 +24,10 @@ export default class RemoteTrackPublication extends TrackPublication {
|
|
24
24
|
|
25
25
|
protected fps?: number;
|
26
26
|
|
27
|
-
constructor(kind: Track.Kind,
|
28
|
-
super(kind,
|
27
|
+
constructor(kind: Track.Kind, ti: TrackInfo, autoSubscribe: boolean | undefined) {
|
28
|
+
super(kind, ti.sid, ti.name);
|
29
29
|
this.subscribed = autoSubscribe;
|
30
|
+
this.updateInfo(ti);
|
30
31
|
}
|
31
32
|
|
32
33
|
/**
|
@@ -31,9 +31,6 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
31
31
|
) {
|
32
32
|
super(mediaTrack, sid, Track.Kind.Video, receiver);
|
33
33
|
this.adaptiveStreamSettings = adaptiveStreamSettings;
|
34
|
-
if (this.isAdaptiveStream) {
|
35
|
-
this.streamState = Track.StreamState.Paused;
|
36
|
-
}
|
37
34
|
}
|
38
35
|
|
39
36
|
get isAdaptiveStream(): boolean {
|
package/src/room/track/Track.ts
CHANGED
@@ -32,7 +32,8 @@ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter
|
|
32
32
|
mediaStream?: MediaStream;
|
33
33
|
|
34
34
|
/**
|
35
|
-
* indicates current state of stream
|
35
|
+
* indicates current state of stream, it'll indicate `paused` if the track
|
36
|
+
* has been paused by congestion controller
|
36
37
|
*/
|
37
38
|
streamState: Track.StreamState = Track.StreamState.Active;
|
38
39
|
|
@@ -28,12 +28,12 @@ export interface TrackPublishDefaults {
|
|
28
28
|
audioBitrate?: number;
|
29
29
|
|
30
30
|
/**
|
31
|
-
* dtx (Discontinuous Transmission of audio),
|
31
|
+
* dtx (Discontinuous Transmission of audio), enabled by default for mono tracks.
|
32
32
|
*/
|
33
33
|
dtx?: boolean;
|
34
34
|
|
35
35
|
/**
|
36
|
-
* red (Redundant Audio Data),
|
36
|
+
* red (Redundant Audio Data), enabled by default for mono tracks.
|
37
37
|
*/
|
38
38
|
red?: boolean;
|
39
39
|
|
@@ -133,6 +133,18 @@ export interface ScreenShareCaptureOptions {
|
|
133
133
|
|
134
134
|
/** capture resolution, defaults to full HD */
|
135
135
|
resolution?: VideoResolution;
|
136
|
+
|
137
|
+
/** a CaptureController object instance containing methods that can be used to further manipulate the capture session if included. */
|
138
|
+
controller?: unknown; // TODO replace type with CaptureController once it lands in TypeScript
|
139
|
+
|
140
|
+
/** specifies whether the browser should allow the user to select the current tab for capture */
|
141
|
+
selfBrowserSurface?: 'include' | 'exclude';
|
142
|
+
|
143
|
+
/** specifies whether the browser should display a control to allow the user to dynamically switch the shared tab during screen-sharing. */
|
144
|
+
surfaceSwitching?: 'include' | 'exclude';
|
145
|
+
|
146
|
+
/** specifies whether the browser should include the system audio among the possible audio sources offered to the user */
|
147
|
+
systemAudio?: 'include' | 'exclude';
|
136
148
|
}
|
137
149
|
|
138
150
|
export interface AudioCaptureOptions {
|
package/src/room/types.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import type RemoteParticipant from './participant/RemoteParticipant';
|
2
|
+
|
1
3
|
export type SimulationOptions = {
|
2
4
|
publish?: {
|
3
5
|
audio?: boolean;
|
@@ -11,3 +13,10 @@ export type SimulationOptions = {
|
|
11
13
|
video?: boolean;
|
12
14
|
};
|
13
15
|
};
|
16
|
+
|
17
|
+
export type DataPublishOptions = {
|
18
|
+
/** the participants who will receive the message, will be sent to every one if empty */
|
19
|
+
destination?: RemoteParticipant[] | string[];
|
20
|
+
/** the topic under which the message gets published */
|
21
|
+
topic?: string;
|
22
|
+
};
|
package/src/version.ts
CHANGED