livekit-client 1.11.4 → 1.12.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +13 -1
- package/dist/livekit-client.e2ee.worker.js +2 -0
- package/dist/livekit-client.e2ee.worker.js.map +1 -0
- package/dist/livekit-client.e2ee.worker.mjs +1545 -0
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -0
- package/dist/livekit-client.esm.mjs +4786 -4065
- 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/api/SignalClient.d.ts +4 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/turn.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/websocket.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +45 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -0
- package/dist/src/e2ee/KeyProvider.d.ts +42 -0
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -0
- package/dist/src/e2ee/constants.d.ts +14 -0
- package/dist/src/e2ee/constants.d.ts.map +1 -0
- package/dist/src/e2ee/errors.d.ts +11 -0
- package/dist/src/e2ee/errors.d.ts.map +1 -0
- package/dist/src/e2ee/index.d.ts +4 -0
- package/dist/src/e2ee/index.d.ts.map +1 -0
- package/dist/src/e2ee/types.d.ts +129 -0
- package/dist/src/e2ee/types.d.ts.map +1 -0
- package/dist/src/e2ee/utils.d.ts +24 -0
- package/dist/src/e2ee/utils.d.ts.map +1 -0
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +174 -0
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -0
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +54 -0
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -0
- package/dist/src/e2ee/worker/e2ee.worker.d.ts +2 -0
- package/dist/src/e2ee/worker/e2ee.worker.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +4 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/options.d.ts +5 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/proto/livekit_models.d.ts +2 -2
- package/dist/src/proto/livekit_models.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +3 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +17 -3
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +10 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +14 -2
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +7 -2
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +6 -4
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts +3 -0
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +2 -2
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +9 -0
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +2 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/MockMediaStreamTrack.d.ts.map +1 -1
- package/dist/src/utils/browserParser.d.ts +2 -0
- package/dist/src/utils/browserParser.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +4 -1
- package/dist/ts4.2/src/e2ee/E2eeManager.d.ts +45 -0
- package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +42 -0
- package/dist/ts4.2/src/e2ee/constants.d.ts +14 -0
- package/dist/ts4.2/src/e2ee/errors.d.ts +11 -0
- package/dist/ts4.2/src/e2ee/index.d.ts +4 -0
- package/dist/ts4.2/src/e2ee/types.d.ts +129 -0
- package/dist/ts4.2/src/e2ee/utils.d.ts +24 -0
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +174 -0
- package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +54 -0
- package/dist/ts4.2/src/e2ee/worker/e2ee.worker.d.ts +2 -0
- package/dist/ts4.2/src/index.d.ts +1 -0
- package/dist/ts4.2/src/logger.d.ts +4 -1
- package/dist/ts4.2/src/options.d.ts +5 -0
- package/dist/ts4.2/src/proto/livekit_models.d.ts +2 -2
- package/dist/ts4.2/src/room/PCTransport.d.ts +3 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +17 -3
- package/dist/ts4.2/src/room/Room.d.ts +10 -0
- package/dist/ts4.2/src/room/events.d.ts +14 -2
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +7 -2
- package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +6 -4
- package/dist/ts4.2/src/room/track/TrackPublication.d.ts +3 -0
- package/dist/ts4.2/src/room/track/options.d.ts +6 -6
- package/dist/ts4.2/src/room/track/utils.d.ts +9 -0
- package/dist/ts4.2/src/room/utils.d.ts +2 -0
- package/dist/ts4.2/src/utils/browserParser.d.ts +2 -0
- package/package.json +17 -7
- package/src/api/SignalClient.ts +28 -9
- package/src/connectionHelper/checks/turn.ts +1 -0
- package/src/connectionHelper/checks/websocket.ts +1 -0
- package/src/e2ee/E2eeManager.ts +374 -0
- package/src/e2ee/KeyProvider.ts +77 -0
- package/src/e2ee/constants.ts +40 -0
- package/src/e2ee/errors.ts +16 -0
- package/src/e2ee/index.ts +3 -0
- package/src/e2ee/types.ts +160 -0
- package/src/e2ee/utils.ts +127 -0
- package/src/e2ee/worker/FrameCryptor.test.ts +21 -0
- package/src/e2ee/worker/FrameCryptor.ts +612 -0
- package/src/e2ee/worker/ParticipantKeyHandler.ts +144 -0
- package/src/e2ee/worker/e2ee.worker.ts +223 -0
- package/src/e2ee/worker/tsconfig.json +6 -0
- package/src/index.ts +1 -0
- package/src/logger.ts +10 -2
- package/src/options.ts +6 -0
- package/src/proto/livekit_models.ts +12 -12
- package/src/room/PCTransport.ts +39 -9
- package/src/room/RTCEngine.ts +127 -34
- package/src/room/Room.ts +94 -29
- package/src/room/defaults.ts +1 -1
- package/src/room/events.ts +14 -0
- package/src/room/participant/LocalParticipant.ts +52 -8
- package/src/room/participant/Participant.ts +4 -0
- package/src/room/participant/RemoteParticipant.ts +19 -15
- package/src/room/track/LocalTrack.ts +5 -4
- package/src/room/track/RemoteVideoTrack.ts +2 -2
- package/src/room/track/TrackPublication.ts +9 -1
- package/src/room/track/create.ts +9 -0
- package/src/room/track/options.ts +3 -2
- package/src/room/track/utils.ts +27 -0
- package/src/room/utils.ts +5 -0
- package/src/room/worker.d.ts +4 -0
- package/src/test/MockMediaStreamTrack.ts +1 -0
- package/src/utils/browserParser.ts +5 -0
@@ -1,6 +1,12 @@
|
|
1
1
|
import log from '../../logger';
|
2
2
|
import type { InternalRoomOptions } from '../../options';
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
DataPacket,
|
5
|
+
DataPacket_Kind,
|
6
|
+
Encryption_Type,
|
7
|
+
ParticipantInfo,
|
8
|
+
ParticipantPermission,
|
9
|
+
} from '../../proto/livekit_models';
|
4
10
|
import {
|
5
11
|
AddTrackRequest,
|
6
12
|
DataChannelInfo,
|
@@ -68,6 +74,8 @@ export default class LocalParticipant extends Participant {
|
|
68
74
|
// keep a pointer to room options
|
69
75
|
private roomOptions: InternalRoomOptions;
|
70
76
|
|
77
|
+
private encryptionType: Encryption_Type = Encryption_Type.NONE;
|
78
|
+
|
71
79
|
private reconnectFuture?: Future<void>;
|
72
80
|
|
73
81
|
/** @internal */
|
@@ -214,6 +222,22 @@ export default class LocalParticipant extends Participant {
|
|
214
222
|
return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options, publishOptions);
|
215
223
|
}
|
216
224
|
|
225
|
+
/** @internal */
|
226
|
+
setPermissions(permissions: ParticipantPermission): boolean {
|
227
|
+
const prevPermissions = this.permissions;
|
228
|
+
const changed = super.setPermissions(permissions);
|
229
|
+
if (changed && prevPermissions) {
|
230
|
+
this.emit(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions);
|
231
|
+
}
|
232
|
+
return changed;
|
233
|
+
}
|
234
|
+
|
235
|
+
/** @internal */
|
236
|
+
async setE2EEEnabled(enabled: boolean) {
|
237
|
+
this.encryptionType = enabled ? Encryption_Type.GCM : Encryption_Type.NONE;
|
238
|
+
await this.republishAllTracks(undefined, false);
|
239
|
+
}
|
240
|
+
|
217
241
|
/**
|
218
242
|
* Enable or disable publishing for a track by source. This serves as a simple
|
219
243
|
* way to manage the common tracks (camera, mic, or screen share).
|
@@ -552,6 +576,12 @@ export default class LocalParticipant extends Participant {
|
|
552
576
|
...options,
|
553
577
|
};
|
554
578
|
|
579
|
+
// disable simulcast if e2ee is set on safari
|
580
|
+
if (isSafari() && this.roomOptions.e2ee) {
|
581
|
+
log.info(`End-to-end encryption is set up, simulcast publishing will be disabled on Safari`);
|
582
|
+
opts.simulcast = false;
|
583
|
+
}
|
584
|
+
|
555
585
|
if (opts.source) {
|
556
586
|
track.source = opts.source;
|
557
587
|
}
|
@@ -624,8 +654,9 @@ export default class LocalParticipant extends Participant {
|
|
624
654
|
muted: track.isMuted,
|
625
655
|
source: Track.sourceToProto(track.source),
|
626
656
|
disableDtx: !(opts.dtx ?? true),
|
657
|
+
encryption: this.encryptionType,
|
627
658
|
stereo: isStereo,
|
628
|
-
disableRed: !(opts.red ?? true),
|
659
|
+
// disableRed: !(opts.red ?? true),
|
629
660
|
});
|
630
661
|
|
631
662
|
// compute encodings and layers for video
|
@@ -760,11 +791,11 @@ export default class LocalParticipant extends Participant {
|
|
760
791
|
|
761
792
|
if (encodings) {
|
762
793
|
if (isFireFox() && track.kind === Track.Kind.Audio) {
|
763
|
-
/* Refer to RFC https://datatracker.ietf.org/doc/html/rfc7587#section-6.1,
|
794
|
+
/* Refer to RFC https://datatracker.ietf.org/doc/html/rfc7587#section-6.1,
|
764
795
|
livekit-server uses maxaveragebitrate=510000in the answer sdp to permit client to
|
765
|
-
publish high quality audio track. But firefox always uses this value as the actual
|
796
|
+
publish high quality audio track. But firefox always uses this value as the actual
|
766
797
|
bitrates, causing the audio bitrates to rise to 510Kbps in any stereo case unexpectedly.
|
767
|
-
So the client need to modify maxaverragebitrates in answer sdp to user provided value to
|
798
|
+
So the client need to modify maxaverragebitrates in answer sdp to user provided value to
|
768
799
|
fix the issue.
|
769
800
|
*/
|
770
801
|
let trackTransceiver: RTCRtpTransceiver | undefined = undefined;
|
@@ -790,7 +821,7 @@ export default class LocalParticipant extends Participant {
|
|
790
821
|
}
|
791
822
|
}
|
792
823
|
|
793
|
-
this.engine.negotiate();
|
824
|
+
await this.engine.negotiate();
|
794
825
|
|
795
826
|
if (track instanceof LocalVideoTrack) {
|
796
827
|
track.startMonitor(this.engine.client);
|
@@ -876,7 +907,7 @@ export default class LocalParticipant extends Participant {
|
|
876
907
|
}
|
877
908
|
await this.engine.createSimulcastSender(track, simulcastTrack, opts, encodings);
|
878
909
|
|
879
|
-
this.engine.negotiate();
|
910
|
+
await this.engine.negotiate();
|
880
911
|
log.debug(`published ${videoCodec} for track ${track.sid}`, { encodings, trackInfo: ti });
|
881
912
|
}
|
882
913
|
|
@@ -980,7 +1011,7 @@ export default class LocalParticipant extends Participant {
|
|
980
1011
|
) as LocalTrackPublication[];
|
981
1012
|
}
|
982
1013
|
|
983
|
-
async republishAllTracks(options?: TrackPublishOptions) {
|
1014
|
+
async republishAllTracks(options?: TrackPublishOptions, restartTracks: boolean = true) {
|
984
1015
|
const localPubs: LocalTrackPublication[] = [];
|
985
1016
|
this.tracks.forEach((pub) => {
|
986
1017
|
if (pub.track) {
|
@@ -995,6 +1026,19 @@ export default class LocalParticipant extends Participant {
|
|
995
1026
|
localPubs.map(async (pub) => {
|
996
1027
|
const track = pub.track!;
|
997
1028
|
await this.unpublishTrack(track, false);
|
1029
|
+
if (
|
1030
|
+
restartTracks &&
|
1031
|
+
!track.isMuted &&
|
1032
|
+
(track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) &&
|
1033
|
+
!track.isUserProvided
|
1034
|
+
) {
|
1035
|
+
// generally we need to restart the track before publishing, often a full reconnect
|
1036
|
+
// is necessary because computer had gone to sleep.
|
1037
|
+
log.debug('restarting existing track', {
|
1038
|
+
track: pub.trackSid,
|
1039
|
+
});
|
1040
|
+
await track.restartTrack();
|
1041
|
+
}
|
998
1042
|
await this.publishTrack(track, pub.options);
|
999
1043
|
}),
|
1000
1044
|
);
|
@@ -68,6 +68,10 @@ export default class Participant extends EventEmitter<ParticipantEventCallbacks>
|
|
68
68
|
|
69
69
|
private _connectionQuality: ConnectionQuality = ConnectionQuality.Unknown;
|
70
70
|
|
71
|
+
get isEncrypted() {
|
72
|
+
return this.tracks.size > 0 && Array.from(this.tracks.values()).every((tr) => tr.isEncrypted);
|
73
|
+
}
|
74
|
+
|
71
75
|
/** @internal */
|
72
76
|
constructor(sid: string, identity: string, name?: string, metadata?: string) {
|
73
77
|
super();
|
@@ -24,7 +24,7 @@ export default class RemoteParticipant extends Participant {
|
|
24
24
|
|
25
25
|
signalClient: SignalClient;
|
26
26
|
|
27
|
-
private
|
27
|
+
private volumeMap: Map<Track.Source, number>;
|
28
28
|
|
29
29
|
private audioContext?: AudioContext;
|
30
30
|
|
@@ -48,6 +48,7 @@ export default class RemoteParticipant extends Participant {
|
|
48
48
|
this.tracks = new Map();
|
49
49
|
this.audioTracks = new Map();
|
50
50
|
this.videoTracks = new Map();
|
51
|
+
this.volumeMap = new Map();
|
51
52
|
}
|
52
53
|
|
53
54
|
protected addTrackPublication(publication: RemoteTrackPublication) {
|
@@ -102,12 +103,17 @@ export default class RemoteParticipant extends Participant {
|
|
102
103
|
}
|
103
104
|
|
104
105
|
/**
|
105
|
-
* sets the volume on the participant's
|
106
|
+
* sets the volume on the participant's audio track
|
107
|
+
* by default, this affects the microphone publication
|
108
|
+
* a different source can be passed in as a second argument
|
106
109
|
* if no track exists the volume will be applied when the microphone track is added
|
107
110
|
*/
|
108
|
-
setVolume(
|
109
|
-
|
110
|
-
|
111
|
+
setVolume(
|
112
|
+
volume: number,
|
113
|
+
source: Track.Source.Microphone | Track.Source.ScreenShareAudio = Track.Source.Microphone,
|
114
|
+
) {
|
115
|
+
this.volumeMap.set(source, volume);
|
116
|
+
const audioPublication = this.getTrack(source);
|
111
117
|
if (audioPublication && audioPublication.track) {
|
112
118
|
(audioPublication.track as RemoteAudioTrack).setVolume(volume);
|
113
119
|
}
|
@@ -116,12 +122,14 @@ export default class RemoteParticipant extends Participant {
|
|
116
122
|
/**
|
117
123
|
* gets the volume on the participant's microphone track
|
118
124
|
*/
|
119
|
-
getVolume(
|
120
|
-
|
125
|
+
getVolume(
|
126
|
+
source: Track.Source.Microphone | Track.Source.ScreenShareAudio = Track.Source.Microphone,
|
127
|
+
) {
|
128
|
+
const audioPublication = this.getTrack(source);
|
121
129
|
if (audioPublication && audioPublication.track) {
|
122
130
|
return (audioPublication.track as RemoteAudioTrack).getVolume();
|
123
131
|
}
|
124
|
-
return this.
|
132
|
+
return this.volumeMap.get(source);
|
125
133
|
}
|
126
134
|
|
127
135
|
/** @internal */
|
@@ -198,13 +206,9 @@ export default class RemoteParticipant extends Participant {
|
|
198
206
|
track.start();
|
199
207
|
|
200
208
|
publication.setTrack(track);
|
201
|
-
// set participant
|
202
|
-
if (
|
203
|
-
this.
|
204
|
-
track instanceof RemoteAudioTrack &&
|
205
|
-
track.source === Track.Source.Microphone
|
206
|
-
) {
|
207
|
-
track.setVolume(this.volume);
|
209
|
+
// set participant volumes on new audio tracks
|
210
|
+
if (this.volumeMap.has(publication.source) && track instanceof RemoteAudioTrack) {
|
211
|
+
track.setVolume(this.volumeMap.get(publication.source)!);
|
208
212
|
}
|
209
213
|
|
210
214
|
return publication;
|
@@ -56,9 +56,10 @@ export default abstract class LocalTrack extends Track {
|
|
56
56
|
this.muteLock = new Mutex();
|
57
57
|
this.pauseUpstreamLock = new Mutex();
|
58
58
|
this.processorLock = new Mutex();
|
59
|
+
this.setMediaStreamTrack(mediaTrack, true);
|
60
|
+
|
59
61
|
// added to satisfy TS compiler, constraints are synced with MediaStreamTrack
|
60
62
|
this._constraints = mediaTrack.getConstraints();
|
61
|
-
this.setMediaStreamTrack(mediaTrack);
|
62
63
|
if (constraints) {
|
63
64
|
this._constraints = constraints;
|
64
65
|
}
|
@@ -97,8 +98,8 @@ export default abstract class LocalTrack extends Track {
|
|
97
98
|
return this.processor?.processedTrack ?? this._mediaStreamTrack;
|
98
99
|
}
|
99
100
|
|
100
|
-
private async setMediaStreamTrack(newTrack: MediaStreamTrack) {
|
101
|
-
if (newTrack === this._mediaStreamTrack) {
|
101
|
+
private async setMediaStreamTrack(newTrack: MediaStreamTrack, force?: boolean) {
|
102
|
+
if (newTrack === this._mediaStreamTrack && !force) {
|
102
103
|
return;
|
103
104
|
}
|
104
105
|
if (this._mediaStreamTrack) {
|
@@ -109,7 +110,7 @@ export default abstract class LocalTrack extends Track {
|
|
109
110
|
this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
|
110
111
|
this._mediaStreamTrack.removeEventListener('mute', this.pauseUpstream);
|
111
112
|
this._mediaStreamTrack.removeEventListener('unmute', this.resumeUpstream);
|
112
|
-
if (!this.providedByUser) {
|
113
|
+
if (!this.providedByUser && this._mediaStreamTrack !== newTrack) {
|
113
114
|
this._mediaStreamTrack.stop();
|
114
115
|
}
|
115
116
|
}
|
@@ -123,6 +123,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
123
123
|
}
|
124
124
|
this.elementInfos = this.elementInfos.filter((info) => info !== elementInfo);
|
125
125
|
this.updateVisibility();
|
126
|
+
this.debouncedHandleResize();
|
126
127
|
}
|
127
128
|
|
128
129
|
detach(): HTMLMediaElement[];
|
@@ -195,9 +196,8 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
195
196
|
private stopObservingElement(element: HTMLMediaElement) {
|
196
197
|
const stopElementInfos = this.elementInfos.filter((info) => info.element === element);
|
197
198
|
for (const info of stopElementInfos) {
|
198
|
-
|
199
|
+
this.stopObservingElementInfo(info);
|
199
200
|
}
|
200
|
-
this.elementInfos = this.elementInfos.filter((info) => info.element !== element);
|
201
201
|
}
|
202
202
|
|
203
203
|
protected async handleAppVisibilityChanged() {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import EventEmitter from 'eventemitter3';
|
2
2
|
import log from '../../logger';
|
3
|
+
import { Encryption_Type } from '../../proto/livekit_models';
|
3
4
|
import type { SubscriptionError, TrackInfo } from '../../proto/livekit_models';
|
4
5
|
import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc';
|
5
6
|
import { TrackEvent } from '../events';
|
@@ -35,6 +36,8 @@ export class TrackPublication extends EventEmitter<PublicationEventCallbacks> {
|
|
35
36
|
|
36
37
|
protected metadataMuted: boolean = false;
|
37
38
|
|
39
|
+
protected encryption: Encryption_Type = Encryption_Type.NONE;
|
40
|
+
|
38
41
|
constructor(kind: Track.Kind, id: string, name: string) {
|
39
42
|
super();
|
40
43
|
this.kind = kind;
|
@@ -71,6 +74,10 @@ export class TrackPublication extends EventEmitter<PublicationEventCallbacks> {
|
|
71
74
|
return this.track !== undefined;
|
72
75
|
}
|
73
76
|
|
77
|
+
get isEncrypted(): boolean {
|
78
|
+
return this.encryption !== Encryption_Type.NONE;
|
79
|
+
}
|
80
|
+
|
74
81
|
/**
|
75
82
|
* an [AudioTrack] if this publication holds an audio track
|
76
83
|
*/
|
@@ -110,8 +117,9 @@ export class TrackPublication extends EventEmitter<PublicationEventCallbacks> {
|
|
110
117
|
};
|
111
118
|
this.simulcasted = info.simulcast;
|
112
119
|
}
|
120
|
+
this.encryption = info.encryption;
|
113
121
|
this.trackInfo = info;
|
114
|
-
log.
|
122
|
+
log.debug('update publication info', { info });
|
115
123
|
}
|
116
124
|
}
|
117
125
|
|
package/src/room/track/create.ts
CHANGED
@@ -57,6 +57,15 @@ export async function createLocalTracks(
|
|
57
57
|
if (typeof conOrBool !== 'boolean') {
|
58
58
|
trackConstraints = conOrBool;
|
59
59
|
}
|
60
|
+
|
61
|
+
// update the constraints with the device id the user gave permissions to in the permission prompt
|
62
|
+
// otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
|
63
|
+
if (trackConstraints) {
|
64
|
+
trackConstraints.deviceId = mediaStreamTrack.getSettings().deviceId;
|
65
|
+
} else {
|
66
|
+
trackConstraints = { deviceId: mediaStreamTrack.getSettings().deviceId };
|
67
|
+
}
|
68
|
+
|
60
69
|
const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints);
|
61
70
|
if (track.kind === Track.Kind.Video) {
|
62
71
|
track.source = Track.Source.Camera;
|
@@ -272,10 +272,11 @@ export interface AudioPreset {
|
|
272
272
|
priority?: RTCPriorityType;
|
273
273
|
}
|
274
274
|
|
275
|
-
const codecs = ['vp8', 'h264', 'vp9', 'av1'] as const;
|
276
275
|
const backupCodecs = ['vp8', 'h264'] as const;
|
277
276
|
|
278
|
-
export
|
277
|
+
export const videoCodecs = ['vp8', 'h264', 'vp9', 'av1'] as const;
|
278
|
+
|
279
|
+
export type VideoCodec = (typeof videoCodecs)[number];
|
279
280
|
|
280
281
|
export type BackupVideoCodec = (typeof backupCodecs)[number];
|
281
282
|
|
package/src/room/track/utils.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { sleep } from '../utils';
|
2
|
+
import { Track } from './Track';
|
2
3
|
import type { AudioCaptureOptions, CreateLocalTracksOptions, VideoCaptureOptions } from './options';
|
3
4
|
import type { AudioTrack } from './types';
|
4
5
|
|
@@ -112,3 +113,29 @@ export function getNewAudioContext(): AudioContext | void {
|
|
112
113
|
return new AudioContext({ latencyHint: 'interactive' });
|
113
114
|
}
|
114
115
|
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* @internal
|
119
|
+
*/
|
120
|
+
export function kindToSource(kind: MediaDeviceKind) {
|
121
|
+
if (kind === 'audioinput') {
|
122
|
+
return Track.Source.Microphone;
|
123
|
+
} else if (kind === 'videoinput') {
|
124
|
+
return Track.Source.Camera;
|
125
|
+
} else {
|
126
|
+
return Track.Source.Unknown;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* @internal
|
132
|
+
*/
|
133
|
+
export function sourceToKind(source: Track.Source): MediaDeviceKind | undefined {
|
134
|
+
if (source === Track.Source.Microphone) {
|
135
|
+
return 'audioinput';
|
136
|
+
} else if (source === Track.Source.Camera) {
|
137
|
+
return 'videoinput';
|
138
|
+
} else {
|
139
|
+
return undefined;
|
140
|
+
}
|
141
|
+
}
|
package/src/room/utils.ts
CHANGED
@@ -4,6 +4,7 @@ import type { DetectableBrowser } from '../utils/browserParser';
|
|
4
4
|
import { protocolVersion, version } from '../version';
|
5
5
|
import type LocalAudioTrack from './track/LocalAudioTrack';
|
6
6
|
import type RemoteAudioTrack from './track/RemoteAudioTrack';
|
7
|
+
import { VideoCodec, videoCodecs } from './track/options';
|
7
8
|
import { getNewAudioContext } from './track/utils';
|
8
9
|
import type { LiveKitReactNativeInfo } from './types';
|
9
10
|
|
@@ -456,6 +457,10 @@ export class Mutex {
|
|
456
457
|
}
|
457
458
|
}
|
458
459
|
|
460
|
+
export function isVideoCodec(maybeCodec: string): maybeCodec is VideoCodec {
|
461
|
+
return videoCodecs.includes(maybeCodec as VideoCodec);
|
462
|
+
}
|
463
|
+
|
459
464
|
export function unwrapConstraint(constraint: ConstrainDOMString): string {
|
460
465
|
if (typeof constraint === 'string') {
|
461
466
|
return constraint;
|
@@ -4,10 +4,12 @@
|
|
4
4
|
const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i;
|
5
5
|
|
6
6
|
export type DetectableBrowser = 'Chrome' | 'Firefox' | 'Safari';
|
7
|
+
export type DetectableOS = 'iOS' | 'macOS';
|
7
8
|
|
8
9
|
export type BrowserDetails = {
|
9
10
|
name: DetectableBrowser;
|
10
11
|
version: string;
|
12
|
+
os?: DetectableOS;
|
11
13
|
};
|
12
14
|
|
13
15
|
let browserDetails: BrowserDetails | undefined;
|
@@ -34,6 +36,7 @@ const browsersList = [
|
|
34
36
|
const browser: BrowserDetails = {
|
35
37
|
name: 'Firefox',
|
36
38
|
version: getMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua),
|
39
|
+
os: ua.toLowerCase().includes('fxios') ? 'iOS' : undefined,
|
37
40
|
};
|
38
41
|
return browser;
|
39
42
|
},
|
@@ -44,6 +47,7 @@ const browsersList = [
|
|
44
47
|
const browser: BrowserDetails = {
|
45
48
|
name: 'Chrome',
|
46
49
|
version: getMatch(/(?:chrome|chromium|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua),
|
50
|
+
os: ua.toLowerCase().includes('crios') ? 'iOS' : undefined,
|
47
51
|
};
|
48
52
|
|
49
53
|
return browser;
|
@@ -56,6 +60,7 @@ const browsersList = [
|
|
56
60
|
const browser: BrowserDetails = {
|
57
61
|
name: 'Safari',
|
58
62
|
version: getMatch(commonVersionIdentifier, ua),
|
63
|
+
os: ua.includes('Mobile/') ? 'iOS' : 'macOS',
|
59
64
|
};
|
60
65
|
|
61
66
|
return browser;
|