livekit-client 2.13.1 → 2.13.2
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/livekit-client.esm.mjs +298 -73
- 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/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +5 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/defaults.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +5 -1
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +9 -0
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +10 -0
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +1 -0
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +8 -0
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/record.d.ts +6 -0
- package/dist/src/room/track/record.d.ts.map +1 -0
- package/dist/ts4.2/src/index.d.ts +1 -0
- package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -1
- package/dist/ts4.2/src/room/Room.d.ts +4 -0
- package/dist/ts4.2/src/room/events.d.ts +5 -1
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +9 -0
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +10 -0
- package/dist/ts4.2/src/room/track/Track.d.ts +1 -0
- package/dist/ts4.2/src/room/track/options.d.ts +8 -0
- package/dist/ts4.2/src/room/track/record.d.ts +6 -0
- package/package.json +3 -2
- package/src/e2ee/worker/tsconfig.json +9 -1
- package/src/index.ts +2 -0
- package/src/room/RTCEngine.ts +2 -5
- package/src/room/Room.ts +14 -2
- package/src/room/defaults.ts +1 -0
- package/src/room/events.ts +5 -0
- package/src/room/participant/LocalParticipant.ts +179 -16
- package/src/room/track/LocalTrack.ts +47 -2
- package/src/room/track/Track.ts +1 -0
- package/src/room/track/options.ts +9 -0
- package/src/room/track/record.ts +51 -0
@@ -11181,6 +11181,10 @@ var TrackEvent;
|
|
11181
11181
|
* @experimental
|
11182
11182
|
*/
|
11183
11183
|
TrackEvent["TimeSyncUpdate"] = "timeSyncUpdate";
|
11184
|
+
/**
|
11185
|
+
* @internal
|
11186
|
+
*/
|
11187
|
+
TrackEvent["PreConnectBufferFlushed"] = "preConnectBufferFlushed";
|
11184
11188
|
})(TrackEvent || (TrackEvent = {}));
|
11185
11189
|
|
11186
11190
|
function cloneDeep(value) {
|
@@ -11262,7 +11266,7 @@ function getOSVersion(ua) {
|
|
11262
11266
|
return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
|
11263
11267
|
}
|
11264
11268
|
|
11265
|
-
var version$1 = "2.13.
|
11269
|
+
var version$1 = "2.13.2";
|
11266
11270
|
|
11267
11271
|
const version = version$1;
|
11268
11272
|
const protocolVersion = 16;
|
@@ -15080,7 +15084,8 @@ const publishDefaults = {
|
|
15080
15084
|
screenShareEncoding: ScreenSharePresets.h1080fps15.encoding,
|
15081
15085
|
stopMicTrackOnMute: false,
|
15082
15086
|
videoCodec: defaultVideoCodec,
|
15083
|
-
backupCodec: true
|
15087
|
+
backupCodec: true,
|
15088
|
+
preConnectBuffer: false
|
15084
15089
|
};
|
15085
15090
|
const audioDefaults = {
|
15086
15091
|
deviceId: {
|
@@ -15528,7 +15533,49 @@ function computeBitrate(currentStats, prevStats) {
|
|
15528
15533
|
return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
|
15529
15534
|
}
|
15530
15535
|
|
15531
|
-
|
15536
|
+
class LocalTrackRecorder extends MediaRecorder {
|
15537
|
+
constructor(track, options) {
|
15538
|
+
super(new MediaStream([track.mediaStreamTrack]), options);
|
15539
|
+
let dataListener;
|
15540
|
+
let streamController;
|
15541
|
+
const isClosed = () => streamController === undefined;
|
15542
|
+
const onStop = () => {
|
15543
|
+
this.removeEventListener('dataavailable', dataListener);
|
15544
|
+
this.removeEventListener('stop', onStop);
|
15545
|
+
this.removeEventListener('error', onError);
|
15546
|
+
streamController === null || streamController === void 0 ? void 0 : streamController.close();
|
15547
|
+
streamController = undefined;
|
15548
|
+
};
|
15549
|
+
const onError = event => {
|
15550
|
+
streamController === null || streamController === void 0 ? void 0 : streamController.error(event);
|
15551
|
+
this.removeEventListener('dataavailable', dataListener);
|
15552
|
+
this.removeEventListener('stop', onStop);
|
15553
|
+
this.removeEventListener('error', onError);
|
15554
|
+
streamController = undefined;
|
15555
|
+
};
|
15556
|
+
this.byteStream = new ReadableStream({
|
15557
|
+
start: controller => {
|
15558
|
+
streamController = controller;
|
15559
|
+
dataListener = event => __awaiter(this, void 0, void 0, function* () {
|
15560
|
+
const arrayBuffer = yield event.data.arrayBuffer();
|
15561
|
+
if (isClosed()) {
|
15562
|
+
return;
|
15563
|
+
}
|
15564
|
+
controller.enqueue(new Uint8Array(arrayBuffer));
|
15565
|
+
});
|
15566
|
+
this.addEventListener('dataavailable', dataListener);
|
15567
|
+
},
|
15568
|
+
cancel: () => {
|
15569
|
+
onStop();
|
15570
|
+
}
|
15571
|
+
});
|
15572
|
+
this.addEventListener('stop', onStop);
|
15573
|
+
this.addEventListener('error', onError);
|
15574
|
+
}
|
15575
|
+
}
|
15576
|
+
|
15577
|
+
const DEFAULT_DIMENSIONS_TIMEOUT = 1000;
|
15578
|
+
const PRE_CONNECT_BUFFER_TIMEOUT = 10000;
|
15532
15579
|
class LocalTrack extends Track {
|
15533
15580
|
/** @internal */
|
15534
15581
|
get sender() {
|
@@ -15541,6 +15588,9 @@ class LocalTrack extends Track {
|
|
15541
15588
|
get constraints() {
|
15542
15589
|
return this._constraints;
|
15543
15590
|
}
|
15591
|
+
get hasPreConnectBuffer() {
|
15592
|
+
return !!this.localTrackRecorder;
|
15593
|
+
}
|
15544
15594
|
/**
|
15545
15595
|
*
|
15546
15596
|
* @param mediaTrack
|
@@ -15696,7 +15746,7 @@ class LocalTrack extends Track {
|
|
15696
15746
|
waitForDimensions() {
|
15697
15747
|
return __awaiter(this, arguments, void 0, function () {
|
15698
15748
|
var _this = this;
|
15699
|
-
let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] :
|
15749
|
+
let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_DIMENSIONS_TIMEOUT;
|
15700
15750
|
return function* () {
|
15701
15751
|
var _a;
|
15702
15752
|
if (_this.kind === Track.Kind.Audio) {
|
@@ -16051,6 +16101,36 @@ class LocalTrack extends Track {
|
|
16051
16101
|
}();
|
16052
16102
|
});
|
16053
16103
|
}
|
16104
|
+
/** @internal */
|
16105
|
+
startPreConnectBuffer() {
|
16106
|
+
let timeslice = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 100;
|
16107
|
+
if (!this.localTrackRecorder) {
|
16108
|
+
this.localTrackRecorder = new LocalTrackRecorder(this, {
|
16109
|
+
mimeType: 'audio/webm;codecs=opus'
|
16110
|
+
});
|
16111
|
+
} else {
|
16112
|
+
this.log.warn('preconnect buffer already started');
|
16113
|
+
return;
|
16114
|
+
}
|
16115
|
+
this.localTrackRecorder.start(timeslice);
|
16116
|
+
this.autoStopPreConnectBuffer = setTimeout(() => {
|
16117
|
+
this.log.warn('preconnect buffer timed out, stopping recording automatically', this.logContext);
|
16118
|
+
this.stopPreConnectBuffer();
|
16119
|
+
}, PRE_CONNECT_BUFFER_TIMEOUT);
|
16120
|
+
}
|
16121
|
+
/** @internal */
|
16122
|
+
stopPreConnectBuffer() {
|
16123
|
+
clearTimeout(this.autoStopPreConnectBuffer);
|
16124
|
+
if (this.localTrackRecorder) {
|
16125
|
+
this.localTrackRecorder.stop();
|
16126
|
+
this.localTrackRecorder = undefined;
|
16127
|
+
}
|
16128
|
+
}
|
16129
|
+
/** @internal */
|
16130
|
+
getPreConnectBuffer() {
|
16131
|
+
var _a;
|
16132
|
+
return (_a = this.localTrackRecorder) === null || _a === void 0 ? void 0 : _a.byteStream;
|
16133
|
+
}
|
16054
16134
|
}
|
16055
16135
|
|
16056
16136
|
class LocalAudioTrack extends LocalTrack {
|
@@ -17497,10 +17577,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
17497
17577
|
this.negotiate();
|
17498
17578
|
}
|
17499
17579
|
this.clientConfiguration = joinResponse.clientConfiguration;
|
17500
|
-
|
17501
|
-
setTimeout(() => {
|
17502
|
-
this.emit(EngineEvent.SignalConnected);
|
17503
|
-
}, 10);
|
17580
|
+
this.emit(EngineEvent.SignalConnected, joinResponse);
|
17504
17581
|
return joinResponse;
|
17505
17582
|
} catch (e) {
|
17506
17583
|
if (e instanceof ConnectionError) {
|
@@ -20053,12 +20130,29 @@ class LocalParticipant extends Participant {
|
|
20053
20130
|
this.updateTrackSubscriptionPermissions();
|
20054
20131
|
};
|
20055
20132
|
this.handleDisconnected = () => {
|
20056
|
-
var _a, _b;
|
20133
|
+
var _a, _b, _c, _d, _e, _f;
|
20057
20134
|
if (this.reconnectFuture) {
|
20058
20135
|
this.reconnectFuture.promise.catch(e => this.log.warn(e.message, this.logContext));
|
20059
20136
|
(_b = (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.reject) === null || _b === void 0 ? void 0 : _b.call(_a, 'Got disconnected during reconnection attempt');
|
20060
20137
|
this.reconnectFuture = undefined;
|
20061
20138
|
}
|
20139
|
+
if (this.signalConnectedFuture) {
|
20140
|
+
(_d = (_c = this.signalConnectedFuture).reject) === null || _d === void 0 ? void 0 : _d.call(_c, 'Got disconnected without signal connected');
|
20141
|
+
this.signalConnectedFuture = undefined;
|
20142
|
+
}
|
20143
|
+
(_f = (_e = this.activeAgentFuture) === null || _e === void 0 ? void 0 : _e.reject) === null || _f === void 0 ? void 0 : _f.call(_e, 'Got disconnected without active agent present');
|
20144
|
+
this.activeAgentFuture = undefined;
|
20145
|
+
this.firstActiveAgent = undefined;
|
20146
|
+
};
|
20147
|
+
this.handleSignalConnected = joinResponse => {
|
20148
|
+
var _a, _b;
|
20149
|
+
if (joinResponse.participant) {
|
20150
|
+
this.updateInfo(joinResponse.participant);
|
20151
|
+
}
|
20152
|
+
if (!this.signalConnectedFuture) {
|
20153
|
+
this.signalConnectedFuture = new Future();
|
20154
|
+
}
|
20155
|
+
(_b = (_a = this.signalConnectedFuture).resolve) === null || _b === void 0 ? void 0 : _b.call(_a);
|
20062
20156
|
};
|
20063
20157
|
this.handleSignalRequestResponse = response => {
|
20064
20158
|
const {
|
@@ -20277,7 +20371,7 @@ class LocalParticipant extends Participant {
|
|
20277
20371
|
pub.unmute();
|
20278
20372
|
}
|
20279
20373
|
});
|
20280
|
-
this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.Disconnected, this.handleDisconnected).on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse).on(EngineEvent.DataPacketReceived, this.handleDataPacket);
|
20374
|
+
this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalConnected, this.handleSignalConnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.Disconnected, this.handleDisconnected).on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse).on(EngineEvent.DataPacketReceived, this.handleDataPacket);
|
20281
20375
|
}
|
20282
20376
|
/**
|
20283
20377
|
* Sets and updates the metadata of the local participant.
|
@@ -20460,6 +20554,12 @@ class LocalParticipant extends Participant {
|
|
20460
20554
|
this.pendingPublishing.delete(source);
|
20461
20555
|
throw e;
|
20462
20556
|
}
|
20557
|
+
for (const localTrack of localTracks) {
|
20558
|
+
if (source === Track.Source.Microphone && isAudioTrack(localTrack) && (publishOptions === null || publishOptions === void 0 ? void 0 : publishOptions.preConnectBuffer)) {
|
20559
|
+
this.log.info('starting preconnect buffer for microphone', Object.assign({}, this.logContext));
|
20560
|
+
localTrack.startPreConnectBuffer();
|
20561
|
+
}
|
20562
|
+
}
|
20463
20563
|
try {
|
20464
20564
|
const publishPromises = [];
|
20465
20565
|
for (const localTrack of localTracks) {
|
@@ -20734,23 +20834,13 @@ class LocalParticipant extends Participant {
|
|
20734
20834
|
this.log.debug('deferring track publication until signal is connected', Object.assign(Object.assign({}, this.logContext), {
|
20735
20835
|
track: getLogContextFromTrack(track)
|
20736
20836
|
}));
|
20737
|
-
const
|
20738
|
-
try {
|
20739
|
-
const publication = yield this.publish(track, opts, isStereo);
|
20740
|
-
resolve(publication);
|
20741
|
-
} catch (e) {
|
20742
|
-
reject(e);
|
20743
|
-
}
|
20744
|
-
});
|
20745
|
-
setTimeout(() => {
|
20746
|
-
this.engine.off(EngineEvent.SignalConnected, onSignalConnected);
|
20837
|
+
const timeout = setTimeout(() => {
|
20747
20838
|
reject(new PublishTrackError('publishing rejected as engine not connected within timeout', 408));
|
20748
20839
|
}, 15000);
|
20749
|
-
this.
|
20750
|
-
|
20751
|
-
|
20752
|
-
|
20753
|
-
});
|
20840
|
+
yield this.waitUntilEngineConnected();
|
20841
|
+
clearTimeout(timeout);
|
20842
|
+
const publication = yield this.publish(track, opts, isStereo);
|
20843
|
+
resolve(publication);
|
20754
20844
|
} else {
|
20755
20845
|
try {
|
20756
20846
|
const publication = yield this.publish(track, opts, isStereo);
|
@@ -20775,6 +20865,12 @@ class LocalParticipant extends Participant {
|
|
20775
20865
|
}();
|
20776
20866
|
});
|
20777
20867
|
}
|
20868
|
+
waitUntilEngineConnected() {
|
20869
|
+
if (!this.signalConnectedFuture) {
|
20870
|
+
this.signalConnectedFuture = new Future();
|
20871
|
+
}
|
20872
|
+
return this.signalConnectedFuture.promise;
|
20873
|
+
}
|
20778
20874
|
hasPermissionsToPublish(track) {
|
20779
20875
|
if (!this.permissions) {
|
20780
20876
|
this.log.warn('no permissions present for publishing track', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
@@ -20832,6 +20928,27 @@ class LocalParticipant extends Participant {
|
|
20832
20928
|
track.on(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused);
|
20833
20929
|
track.on(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed);
|
20834
20930
|
track.on(TrackEvent.AudioTrackFeatureUpdate, this.onTrackFeatureUpdate);
|
20931
|
+
const audioFeatures = [];
|
20932
|
+
const disableDtx = !((_a = opts.dtx) !== null && _a !== void 0 ? _a : true);
|
20933
|
+
const settings = track.getSourceTrackSettings();
|
20934
|
+
if (settings.autoGainControl) {
|
20935
|
+
audioFeatures.push(AudioTrackFeature.TF_AUTO_GAIN_CONTROL);
|
20936
|
+
}
|
20937
|
+
if (settings.echoCancellation) {
|
20938
|
+
audioFeatures.push(AudioTrackFeature.TF_ECHO_CANCELLATION);
|
20939
|
+
}
|
20940
|
+
if (settings.noiseSuppression) {
|
20941
|
+
audioFeatures.push(AudioTrackFeature.TF_NOISE_SUPPRESSION);
|
20942
|
+
}
|
20943
|
+
if (settings.channelCount && settings.channelCount > 1) {
|
20944
|
+
audioFeatures.push(AudioTrackFeature.TF_STEREO);
|
20945
|
+
}
|
20946
|
+
if (disableDtx) {
|
20947
|
+
audioFeatures.push(AudioTrackFeature.TF_NO_DTX);
|
20948
|
+
}
|
20949
|
+
if (isLocalAudioTrack(track) && track.hasPreConnectBuffer) {
|
20950
|
+
audioFeatures.push(AudioTrackFeature.TF_PRECONNECT_BUFFER);
|
20951
|
+
}
|
20835
20952
|
// create track publication from track
|
20836
20953
|
const req = new AddTrackRequest({
|
20837
20954
|
// get local track id for use during publishing
|
@@ -20840,12 +20957,13 @@ class LocalParticipant extends Participant {
|
|
20840
20957
|
type: Track.kindToProto(track.kind),
|
20841
20958
|
muted: track.isMuted,
|
20842
20959
|
source: Track.sourceToProto(track.source),
|
20843
|
-
disableDtx
|
20960
|
+
disableDtx,
|
20844
20961
|
encryption: this.encryptionType,
|
20845
20962
|
stereo: isStereo,
|
20846
20963
|
disableRed: this.isE2EEEnabled || !((_b = opts.red) !== null && _b !== void 0 ? _b : true),
|
20847
20964
|
stream: opts === null || opts === void 0 ? void 0 : opts.stream,
|
20848
|
-
backupCodecPolicy: opts === null || opts === void 0 ? void 0 : opts.backupCodecPolicy
|
20965
|
+
backupCodecPolicy: opts === null || opts === void 0 ? void 0 : opts.backupCodecPolicy,
|
20966
|
+
audioFeatures
|
20849
20967
|
});
|
20850
20968
|
// compute encodings and layers for video
|
20851
20969
|
let encodings;
|
@@ -21033,6 +21151,75 @@ class LocalParticipant extends Participant {
|
|
21033
21151
|
this.addTrackPublication(publication);
|
21034
21152
|
// send event for publication
|
21035
21153
|
this.emit(ParticipantEvent.LocalTrackPublished, publication);
|
21154
|
+
if (isLocalAudioTrack(track) && ti.audioFeatures.includes(AudioTrackFeature.TF_PRECONNECT_BUFFER)) {
|
21155
|
+
const stream = track.getPreConnectBuffer();
|
21156
|
+
// TODO: we're registering the listener after negotiation, so there might be a race
|
21157
|
+
this.on(ParticipantEvent.LocalTrackSubscribed, pub => {
|
21158
|
+
if (pub.trackSid === ti.sid) {
|
21159
|
+
if (!track.hasPreConnectBuffer) {
|
21160
|
+
this.log.warn('subscribe event came to late, buffer already closed', this.logContext);
|
21161
|
+
return;
|
21162
|
+
}
|
21163
|
+
this.log.debug('finished recording preconnect buffer', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21164
|
+
track.stopPreConnectBuffer();
|
21165
|
+
}
|
21166
|
+
});
|
21167
|
+
if (stream) {
|
21168
|
+
const bufferStreamPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
21169
|
+
var _a, e_2, _b, _c;
|
21170
|
+
var _d, _e;
|
21171
|
+
try {
|
21172
|
+
this.log.debug('waiting for agent', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21173
|
+
const agentActiveTimeout = setTimeout(() => {
|
21174
|
+
reject(new Error('agent not active within 10 seconds'));
|
21175
|
+
}, 10000);
|
21176
|
+
const agent = yield this.waitUntilActiveAgentPresent();
|
21177
|
+
clearTimeout(agentActiveTimeout);
|
21178
|
+
this.log.debug('sending preconnect buffer', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21179
|
+
const writer = yield this.streamBytes({
|
21180
|
+
name: 'preconnect-buffer',
|
21181
|
+
mimeType: 'audio/opus',
|
21182
|
+
topic: 'lk.agent.pre-connect-audio-buffer',
|
21183
|
+
destinationIdentities: [agent.identity],
|
21184
|
+
attributes: {
|
21185
|
+
trackId: publication.trackSid,
|
21186
|
+
sampleRate: String((_d = settings.sampleRate) !== null && _d !== void 0 ? _d : '48000'),
|
21187
|
+
channels: String((_e = settings.channelCount) !== null && _e !== void 0 ? _e : '1')
|
21188
|
+
}
|
21189
|
+
});
|
21190
|
+
try {
|
21191
|
+
for (var _f = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a; _f = true) {
|
21192
|
+
_c = stream_1_1.value;
|
21193
|
+
_f = false;
|
21194
|
+
const chunk = _c;
|
21195
|
+
yield writer.write(chunk);
|
21196
|
+
}
|
21197
|
+
} catch (e_2_1) {
|
21198
|
+
e_2 = {
|
21199
|
+
error: e_2_1
|
21200
|
+
};
|
21201
|
+
} finally {
|
21202
|
+
try {
|
21203
|
+
if (!_f && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
|
21204
|
+
} finally {
|
21205
|
+
if (e_2) throw e_2.error;
|
21206
|
+
}
|
21207
|
+
}
|
21208
|
+
yield writer.close();
|
21209
|
+
resolve();
|
21210
|
+
} catch (e) {
|
21211
|
+
reject(e);
|
21212
|
+
}
|
21213
|
+
}));
|
21214
|
+
bufferStreamPromise.then(() => {
|
21215
|
+
this.log.debug('preconnect buffer sent successfully', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21216
|
+
}).catch(e => {
|
21217
|
+
this.log.error('error sending preconnect buffer', Object.assign(Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)), {
|
21218
|
+
error: e
|
21219
|
+
}));
|
21220
|
+
});
|
21221
|
+
}
|
21222
|
+
}
|
21036
21223
|
return publication;
|
21037
21224
|
});
|
21038
21225
|
}
|
@@ -21781,6 +21968,29 @@ class LocalParticipant extends Participant {
|
|
21781
21968
|
});
|
21782
21969
|
return true;
|
21783
21970
|
}
|
21971
|
+
/** @internal */
|
21972
|
+
setActiveAgent(agent) {
|
21973
|
+
var _a, _b, _c, _d;
|
21974
|
+
this.firstActiveAgent = agent;
|
21975
|
+
if (agent && !this.firstActiveAgent) {
|
21976
|
+
this.firstActiveAgent = agent;
|
21977
|
+
}
|
21978
|
+
if (agent) {
|
21979
|
+
(_b = (_a = this.activeAgentFuture) === null || _a === void 0 ? void 0 : _a.resolve) === null || _b === void 0 ? void 0 : _b.call(_a, agent);
|
21980
|
+
} else {
|
21981
|
+
(_d = (_c = this.activeAgentFuture) === null || _c === void 0 ? void 0 : _c.reject) === null || _d === void 0 ? void 0 : _d.call(_c, 'Agent disconnected');
|
21982
|
+
}
|
21983
|
+
this.activeAgentFuture = undefined;
|
21984
|
+
}
|
21985
|
+
waitUntilActiveAgentPresent() {
|
21986
|
+
if (this.firstActiveAgent) {
|
21987
|
+
return Promise.resolve(this.firstActiveAgent);
|
21988
|
+
}
|
21989
|
+
if (!this.activeAgentFuture) {
|
21990
|
+
this.activeAgentFuture = new Future();
|
21991
|
+
}
|
21992
|
+
return this.activeAgentFuture.promise;
|
21993
|
+
}
|
21784
21994
|
getPublicationForTrack(track) {
|
21785
21995
|
let publication;
|
21786
21996
|
this.trackPublications.forEach(pub => {
|
@@ -22974,51 +23184,10 @@ class Room extends eventsExports.EventEmitter {
|
|
22974
23184
|
}
|
22975
23185
|
};
|
22976
23186
|
this.handleDeviceChange = () => __awaiter(this, void 0, void 0, function* () {
|
22977
|
-
var _a
|
22978
|
-
|
22979
|
-
|
22980
|
-
|
22981
|
-
const browser = getBrowser();
|
22982
|
-
if ((browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && browser.os !== 'iOS') {
|
22983
|
-
for (let availableDevice of availableDevices) {
|
22984
|
-
const previousDevice = previousDevices.find(info => info.deviceId === availableDevice.deviceId);
|
22985
|
-
if (previousDevice && previousDevice.label !== '' && previousDevice.kind === availableDevice.kind && previousDevice.label !== availableDevice.label) {
|
22986
|
-
// label has changed on device the same deviceId, indicating that the default device has changed on the OS level
|
22987
|
-
if (this.getActiveDevice(availableDevice.kind) === 'default') {
|
22988
|
-
// emit an active device change event only if the selected output device is actually on `default`
|
22989
|
-
this.emit(RoomEvent.ActiveDeviceChanged, availableDevice.kind, availableDevice.deviceId);
|
22990
|
-
}
|
22991
|
-
}
|
22992
|
-
}
|
22993
|
-
}
|
22994
|
-
const kinds = ['audiooutput', 'audioinput', 'videoinput'];
|
22995
|
-
for (let kind of kinds) {
|
22996
|
-
const targetSource = kindToSource(kind);
|
22997
|
-
const targetPublication = this.localParticipant.getTrackPublication(targetSource);
|
22998
|
-
if (targetPublication && ((_a = targetPublication.track) === null || _a === void 0 ? void 0 : _a.isUserProvided)) {
|
22999
|
-
// if the track is user provided, we don't want to switch devices on behalf of the user
|
23000
|
-
continue;
|
23001
|
-
}
|
23002
|
-
const devicesOfKind = availableDevices.filter(d => d.kind === kind);
|
23003
|
-
const activeDevice = this.getActiveDevice(kind);
|
23004
|
-
if (activeDevice === ((_b = previousDevices.filter(info => info.kind === kind)[0]) === null || _b === void 0 ? void 0 : _b.deviceId)) {
|
23005
|
-
// in Safari the first device is always the default, so we assume a user on the default device would like to switch to the default once it changes
|
23006
|
-
// FF doesn't emit an event when the default device changes, so we perform the same best effort and switch to the new device once connected and if it's the first in the array
|
23007
|
-
if (devicesOfKind.length > 0 && ((_c = devicesOfKind[0]) === null || _c === void 0 ? void 0 : _c.deviceId) !== activeDevice) {
|
23008
|
-
yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
|
23009
|
-
continue;
|
23010
|
-
}
|
23011
|
-
}
|
23012
|
-
if (kind === 'audioinput' && !isSafariBased() || kind === 'videoinput') {
|
23013
|
-
// airpods on Safari need special handling for audioinput as the track doesn't end as soon as you take them out
|
23014
|
-
continue;
|
23015
|
-
}
|
23016
|
-
// switch to first available device if previously active device is not available any more
|
23017
|
-
if (devicesOfKind.length > 0 && !devicesOfKind.find(deviceInfo => deviceInfo.deviceId === this.getActiveDevice(kind)) && (
|
23018
|
-
// avoid switching audio output on safari without explicit user action as it leads to slowed down audio playback
|
23019
|
-
kind !== 'audiooutput' || !isSafariBased())) {
|
23020
|
-
yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
|
23021
|
-
}
|
23187
|
+
var _a;
|
23188
|
+
if (((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.os) !== 'iOS') {
|
23189
|
+
// default devices are non deterministic on iOS, so we don't attempt to select them here
|
23190
|
+
yield this.selectDefaultDevices();
|
23022
23191
|
}
|
23023
23192
|
this.emit(RoomEvent.MediaDevicesChanged);
|
23024
23193
|
});
|
@@ -23923,6 +24092,59 @@ class Room extends eventsExports.EventEmitter {
|
|
23923
24092
|
}
|
23924
24093
|
}
|
23925
24094
|
}
|
24095
|
+
/**
|
24096
|
+
* attempt to select the default devices if the previously selected devices are no longer available after a device change event
|
24097
|
+
*/
|
24098
|
+
selectDefaultDevices() {
|
24099
|
+
return __awaiter(this, void 0, void 0, function* () {
|
24100
|
+
var _a, _b, _c;
|
24101
|
+
const previousDevices = DeviceManager.getInstance().previousDevices;
|
24102
|
+
// check for available devices, but don't request permissions in order to avoid prompts for kinds that haven't been used before
|
24103
|
+
const availableDevices = yield DeviceManager.getInstance().getDevices(undefined, false);
|
24104
|
+
const browser = getBrowser();
|
24105
|
+
if ((browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && browser.os !== 'iOS') {
|
24106
|
+
for (let availableDevice of availableDevices) {
|
24107
|
+
const previousDevice = previousDevices.find(info => info.deviceId === availableDevice.deviceId);
|
24108
|
+
if (previousDevice && previousDevice.label !== '' && previousDevice.kind === availableDevice.kind && previousDevice.label !== availableDevice.label) {
|
24109
|
+
// label has changed on device the same deviceId, indicating that the default device has changed on the OS level
|
24110
|
+
if (this.getActiveDevice(availableDevice.kind) === 'default') {
|
24111
|
+
// emit an active device change event only if the selected output device is actually on `default`
|
24112
|
+
this.emit(RoomEvent.ActiveDeviceChanged, availableDevice.kind, availableDevice.deviceId);
|
24113
|
+
}
|
24114
|
+
}
|
24115
|
+
}
|
24116
|
+
}
|
24117
|
+
const kinds = ['audiooutput', 'audioinput', 'videoinput'];
|
24118
|
+
for (let kind of kinds) {
|
24119
|
+
const targetSource = kindToSource(kind);
|
24120
|
+
const targetPublication = this.localParticipant.getTrackPublication(targetSource);
|
24121
|
+
if (targetPublication && ((_a = targetPublication.track) === null || _a === void 0 ? void 0 : _a.isUserProvided)) {
|
24122
|
+
// if the track is user provided, we don't want to switch devices on behalf of the user
|
24123
|
+
continue;
|
24124
|
+
}
|
24125
|
+
const devicesOfKind = availableDevices.filter(d => d.kind === kind);
|
24126
|
+
const activeDevice = this.getActiveDevice(kind);
|
24127
|
+
if (activeDevice === ((_b = previousDevices.filter(info => info.kind === kind)[0]) === null || _b === void 0 ? void 0 : _b.deviceId)) {
|
24128
|
+
// in Safari the first device is always the default, so we assume a user on the default device would like to switch to the default once it changes
|
24129
|
+
// FF doesn't emit an event when the default device changes, so we perform the same best effort and switch to the new device once connected and if it's the first in the array
|
24130
|
+
if (devicesOfKind.length > 0 && ((_c = devicesOfKind[0]) === null || _c === void 0 ? void 0 : _c.deviceId) !== activeDevice) {
|
24131
|
+
yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
|
24132
|
+
continue;
|
24133
|
+
}
|
24134
|
+
}
|
24135
|
+
if (kind === 'audioinput' && !isSafariBased() || kind === 'videoinput') {
|
24136
|
+
// airpods on Safari need special handling for audioinput as the track doesn't end as soon as you take them out
|
24137
|
+
continue;
|
24138
|
+
}
|
24139
|
+
// switch to first available device if previously active device is not available any more
|
24140
|
+
if (devicesOfKind.length > 0 && !devicesOfKind.find(deviceInfo => deviceInfo.deviceId === this.getActiveDevice(kind)) && (
|
24141
|
+
// avoid switching audio output on safari without explicit user action as it leads to slowed down audio playback
|
24142
|
+
kind !== 'audiooutput' || !isSafariBased())) {
|
24143
|
+
yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
|
24144
|
+
}
|
24145
|
+
}
|
24146
|
+
});
|
24147
|
+
}
|
23926
24148
|
acquireAudioContext() {
|
23927
24149
|
return __awaiter(this, void 0, void 0, function* () {
|
23928
24150
|
var _a, _b;
|
@@ -24036,6 +24258,9 @@ class Room extends eventsExports.EventEmitter {
|
|
24036
24258
|
this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant);
|
24037
24259
|
}).on(ParticipantEvent.Active, () => {
|
24038
24260
|
this.emitWhenConnected(RoomEvent.ParticipantActive, participant);
|
24261
|
+
if (participant.kind === ParticipantInfo_Kind.AGENT) {
|
24262
|
+
this.localParticipant.setActiveAgent(participant);
|
24263
|
+
}
|
24039
24264
|
});
|
24040
24265
|
// update info at the end after callbacks have been set up
|
24041
24266
|
if (info) {
|
@@ -25091,5 +25316,5 @@ function isFacingModeValue(item) {
|
|
25091
25316
|
return item === undefined || allowedValues.includes(item);
|
25092
25317
|
}
|
25093
25318
|
|
25094
|
-
export { AudioPresets, BackupCodecPolicy, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionErrorReason, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, _ as Mutex, NegotiationError, Participant, ParticipantEvent, ParticipantInfo_Kind as ParticipantKind, PublishDataError, PublishTrackError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RpcError, ScreenSharePresets, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, TrackType, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, compareVersions, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isAudioTrack, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isLocalParticipant, isLocalTrack, isRemoteParticipant, isRemoteTrack, isScriptTransformSupported, isVideoFrame, isVideoTrack, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
|
25319
|
+
export { AudioPresets, BackupCodecPolicy, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionErrorReason, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalTrackRecorder, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, _ as Mutex, NegotiationError, Participant, ParticipantEvent, ParticipantInfo_Kind as ParticipantKind, PublishDataError, PublishTrackError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RpcError, ScreenSharePresets, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, TrackType, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, compareVersions, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isAudioTrack, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isLocalParticipant, isLocalTrack, isRemoteParticipant, isRemoteTrack, isScriptTransformSupported, isVideoFrame, isVideoTrack, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
|
25095
25320
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|