livekit-client 2.13.1 → 2.13.3
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 +319 -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 +13 -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 +13 -0
- package/package.json +6 -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 +55 -2
- package/src/room/track/Track.ts +1 -0
- package/src/room/track/options.ts +9 -0
- package/src/room/track/record.ts +75 -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.3";
|
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,66 @@ function computeBitrate(currentStats, prevStats) {
|
|
15528
15533
|
return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
|
15529
15534
|
}
|
15530
15535
|
|
15531
|
-
|
15536
|
+
// Check if MediaRecorder is available
|
15537
|
+
const isMediaRecorderAvailable = typeof MediaRecorder !== 'undefined';
|
15538
|
+
// Fallback class for environments without MediaRecorder
|
15539
|
+
class FallbackRecorder {
|
15540
|
+
constructor() {
|
15541
|
+
throw new Error('MediaRecorder is not available in this environment');
|
15542
|
+
}
|
15543
|
+
}
|
15544
|
+
// Use conditional inheritance to avoid parse-time errors
|
15545
|
+
const RecorderBase = isMediaRecorderAvailable ? MediaRecorder : FallbackRecorder;
|
15546
|
+
class LocalTrackRecorder extends RecorderBase {
|
15547
|
+
constructor(track, options) {
|
15548
|
+
if (!isMediaRecorderAvailable) {
|
15549
|
+
throw new Error('MediaRecorder is not available in this environment');
|
15550
|
+
}
|
15551
|
+
super(new MediaStream([track.mediaStreamTrack]), options);
|
15552
|
+
let dataListener;
|
15553
|
+
let streamController;
|
15554
|
+
const isClosed = () => streamController === undefined;
|
15555
|
+
const onStop = () => {
|
15556
|
+
this.removeEventListener('dataavailable', dataListener);
|
15557
|
+
this.removeEventListener('stop', onStop);
|
15558
|
+
this.removeEventListener('error', onError);
|
15559
|
+
streamController === null || streamController === void 0 ? void 0 : streamController.close();
|
15560
|
+
streamController = undefined;
|
15561
|
+
};
|
15562
|
+
const onError = event => {
|
15563
|
+
streamController === null || streamController === void 0 ? void 0 : streamController.error(event);
|
15564
|
+
this.removeEventListener('dataavailable', dataListener);
|
15565
|
+
this.removeEventListener('stop', onStop);
|
15566
|
+
this.removeEventListener('error', onError);
|
15567
|
+
streamController = undefined;
|
15568
|
+
};
|
15569
|
+
this.byteStream = new ReadableStream({
|
15570
|
+
start: controller => {
|
15571
|
+
streamController = controller;
|
15572
|
+
dataListener = event => __awaiter(this, void 0, void 0, function* () {
|
15573
|
+
const arrayBuffer = yield event.data.arrayBuffer();
|
15574
|
+
if (isClosed()) {
|
15575
|
+
return;
|
15576
|
+
}
|
15577
|
+
controller.enqueue(new Uint8Array(arrayBuffer));
|
15578
|
+
});
|
15579
|
+
this.addEventListener('dataavailable', dataListener);
|
15580
|
+
},
|
15581
|
+
cancel: () => {
|
15582
|
+
onStop();
|
15583
|
+
}
|
15584
|
+
});
|
15585
|
+
this.addEventListener('stop', onStop);
|
15586
|
+
this.addEventListener('error', onError);
|
15587
|
+
}
|
15588
|
+
}
|
15589
|
+
// Helper function to check if recording is supported
|
15590
|
+
function isRecordingSupported() {
|
15591
|
+
return isMediaRecorderAvailable;
|
15592
|
+
}
|
15593
|
+
|
15594
|
+
const DEFAULT_DIMENSIONS_TIMEOUT = 1000;
|
15595
|
+
const PRE_CONNECT_BUFFER_TIMEOUT = 10000;
|
15532
15596
|
class LocalTrack extends Track {
|
15533
15597
|
/** @internal */
|
15534
15598
|
get sender() {
|
@@ -15541,6 +15605,9 @@ class LocalTrack extends Track {
|
|
15541
15605
|
get constraints() {
|
15542
15606
|
return this._constraints;
|
15543
15607
|
}
|
15608
|
+
get hasPreConnectBuffer() {
|
15609
|
+
return !!this.localTrackRecorder;
|
15610
|
+
}
|
15544
15611
|
/**
|
15545
15612
|
*
|
15546
15613
|
* @param mediaTrack
|
@@ -15696,7 +15763,7 @@ class LocalTrack extends Track {
|
|
15696
15763
|
waitForDimensions() {
|
15697
15764
|
return __awaiter(this, arguments, void 0, function () {
|
15698
15765
|
var _this = this;
|
15699
|
-
let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] :
|
15766
|
+
let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_DIMENSIONS_TIMEOUT;
|
15700
15767
|
return function* () {
|
15701
15768
|
var _a;
|
15702
15769
|
if (_this.kind === Track.Kind.Audio) {
|
@@ -16051,6 +16118,40 @@ class LocalTrack extends Track {
|
|
16051
16118
|
}();
|
16052
16119
|
});
|
16053
16120
|
}
|
16121
|
+
/** @internal */
|
16122
|
+
startPreConnectBuffer() {
|
16123
|
+
let timeslice = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 100;
|
16124
|
+
if (!isRecordingSupported()) {
|
16125
|
+
this.log.warn('MediaRecorder is not available, cannot start preconnect buffer', this.logContext);
|
16126
|
+
return;
|
16127
|
+
}
|
16128
|
+
if (!this.localTrackRecorder) {
|
16129
|
+
this.localTrackRecorder = new LocalTrackRecorder(this, {
|
16130
|
+
mimeType: 'audio/webm;codecs=opus'
|
16131
|
+
});
|
16132
|
+
} else {
|
16133
|
+
this.log.warn('preconnect buffer already started');
|
16134
|
+
return;
|
16135
|
+
}
|
16136
|
+
this.localTrackRecorder.start(timeslice);
|
16137
|
+
this.autoStopPreConnectBuffer = setTimeout(() => {
|
16138
|
+
this.log.warn('preconnect buffer timed out, stopping recording automatically', this.logContext);
|
16139
|
+
this.stopPreConnectBuffer();
|
16140
|
+
}, PRE_CONNECT_BUFFER_TIMEOUT);
|
16141
|
+
}
|
16142
|
+
/** @internal */
|
16143
|
+
stopPreConnectBuffer() {
|
16144
|
+
clearTimeout(this.autoStopPreConnectBuffer);
|
16145
|
+
if (this.localTrackRecorder) {
|
16146
|
+
this.localTrackRecorder.stop();
|
16147
|
+
this.localTrackRecorder = undefined;
|
16148
|
+
}
|
16149
|
+
}
|
16150
|
+
/** @internal */
|
16151
|
+
getPreConnectBuffer() {
|
16152
|
+
var _a;
|
16153
|
+
return (_a = this.localTrackRecorder) === null || _a === void 0 ? void 0 : _a.byteStream;
|
16154
|
+
}
|
16054
16155
|
}
|
16055
16156
|
|
16056
16157
|
class LocalAudioTrack extends LocalTrack {
|
@@ -17497,10 +17598,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
17497
17598
|
this.negotiate();
|
17498
17599
|
}
|
17499
17600
|
this.clientConfiguration = joinResponse.clientConfiguration;
|
17500
|
-
|
17501
|
-
setTimeout(() => {
|
17502
|
-
this.emit(EngineEvent.SignalConnected);
|
17503
|
-
}, 10);
|
17601
|
+
this.emit(EngineEvent.SignalConnected, joinResponse);
|
17504
17602
|
return joinResponse;
|
17505
17603
|
} catch (e) {
|
17506
17604
|
if (e instanceof ConnectionError) {
|
@@ -20053,12 +20151,29 @@ class LocalParticipant extends Participant {
|
|
20053
20151
|
this.updateTrackSubscriptionPermissions();
|
20054
20152
|
};
|
20055
20153
|
this.handleDisconnected = () => {
|
20056
|
-
var _a, _b;
|
20154
|
+
var _a, _b, _c, _d, _e, _f;
|
20057
20155
|
if (this.reconnectFuture) {
|
20058
20156
|
this.reconnectFuture.promise.catch(e => this.log.warn(e.message, this.logContext));
|
20059
20157
|
(_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
20158
|
this.reconnectFuture = undefined;
|
20061
20159
|
}
|
20160
|
+
if (this.signalConnectedFuture) {
|
20161
|
+
(_d = (_c = this.signalConnectedFuture).reject) === null || _d === void 0 ? void 0 : _d.call(_c, 'Got disconnected without signal connected');
|
20162
|
+
this.signalConnectedFuture = undefined;
|
20163
|
+
}
|
20164
|
+
(_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');
|
20165
|
+
this.activeAgentFuture = undefined;
|
20166
|
+
this.firstActiveAgent = undefined;
|
20167
|
+
};
|
20168
|
+
this.handleSignalConnected = joinResponse => {
|
20169
|
+
var _a, _b;
|
20170
|
+
if (joinResponse.participant) {
|
20171
|
+
this.updateInfo(joinResponse.participant);
|
20172
|
+
}
|
20173
|
+
if (!this.signalConnectedFuture) {
|
20174
|
+
this.signalConnectedFuture = new Future();
|
20175
|
+
}
|
20176
|
+
(_b = (_a = this.signalConnectedFuture).resolve) === null || _b === void 0 ? void 0 : _b.call(_a);
|
20062
20177
|
};
|
20063
20178
|
this.handleSignalRequestResponse = response => {
|
20064
20179
|
const {
|
@@ -20277,7 +20392,7 @@ class LocalParticipant extends Participant {
|
|
20277
20392
|
pub.unmute();
|
20278
20393
|
}
|
20279
20394
|
});
|
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);
|
20395
|
+
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
20396
|
}
|
20282
20397
|
/**
|
20283
20398
|
* Sets and updates the metadata of the local participant.
|
@@ -20460,6 +20575,12 @@ class LocalParticipant extends Participant {
|
|
20460
20575
|
this.pendingPublishing.delete(source);
|
20461
20576
|
throw e;
|
20462
20577
|
}
|
20578
|
+
for (const localTrack of localTracks) {
|
20579
|
+
if (source === Track.Source.Microphone && isAudioTrack(localTrack) && (publishOptions === null || publishOptions === void 0 ? void 0 : publishOptions.preConnectBuffer)) {
|
20580
|
+
this.log.info('starting preconnect buffer for microphone', Object.assign({}, this.logContext));
|
20581
|
+
localTrack.startPreConnectBuffer();
|
20582
|
+
}
|
20583
|
+
}
|
20463
20584
|
try {
|
20464
20585
|
const publishPromises = [];
|
20465
20586
|
for (const localTrack of localTracks) {
|
@@ -20734,23 +20855,13 @@ class LocalParticipant extends Participant {
|
|
20734
20855
|
this.log.debug('deferring track publication until signal is connected', Object.assign(Object.assign({}, this.logContext), {
|
20735
20856
|
track: getLogContextFromTrack(track)
|
20736
20857
|
}));
|
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);
|
20858
|
+
const timeout = setTimeout(() => {
|
20747
20859
|
reject(new PublishTrackError('publishing rejected as engine not connected within timeout', 408));
|
20748
20860
|
}, 15000);
|
20749
|
-
this.
|
20750
|
-
|
20751
|
-
|
20752
|
-
|
20753
|
-
});
|
20861
|
+
yield this.waitUntilEngineConnected();
|
20862
|
+
clearTimeout(timeout);
|
20863
|
+
const publication = yield this.publish(track, opts, isStereo);
|
20864
|
+
resolve(publication);
|
20754
20865
|
} else {
|
20755
20866
|
try {
|
20756
20867
|
const publication = yield this.publish(track, opts, isStereo);
|
@@ -20775,6 +20886,12 @@ class LocalParticipant extends Participant {
|
|
20775
20886
|
}();
|
20776
20887
|
});
|
20777
20888
|
}
|
20889
|
+
waitUntilEngineConnected() {
|
20890
|
+
if (!this.signalConnectedFuture) {
|
20891
|
+
this.signalConnectedFuture = new Future();
|
20892
|
+
}
|
20893
|
+
return this.signalConnectedFuture.promise;
|
20894
|
+
}
|
20778
20895
|
hasPermissionsToPublish(track) {
|
20779
20896
|
if (!this.permissions) {
|
20780
20897
|
this.log.warn('no permissions present for publishing track', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
@@ -20832,6 +20949,27 @@ class LocalParticipant extends Participant {
|
|
20832
20949
|
track.on(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused);
|
20833
20950
|
track.on(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed);
|
20834
20951
|
track.on(TrackEvent.AudioTrackFeatureUpdate, this.onTrackFeatureUpdate);
|
20952
|
+
const audioFeatures = [];
|
20953
|
+
const disableDtx = !((_a = opts.dtx) !== null && _a !== void 0 ? _a : true);
|
20954
|
+
const settings = track.getSourceTrackSettings();
|
20955
|
+
if (settings.autoGainControl) {
|
20956
|
+
audioFeatures.push(AudioTrackFeature.TF_AUTO_GAIN_CONTROL);
|
20957
|
+
}
|
20958
|
+
if (settings.echoCancellation) {
|
20959
|
+
audioFeatures.push(AudioTrackFeature.TF_ECHO_CANCELLATION);
|
20960
|
+
}
|
20961
|
+
if (settings.noiseSuppression) {
|
20962
|
+
audioFeatures.push(AudioTrackFeature.TF_NOISE_SUPPRESSION);
|
20963
|
+
}
|
20964
|
+
if (settings.channelCount && settings.channelCount > 1) {
|
20965
|
+
audioFeatures.push(AudioTrackFeature.TF_STEREO);
|
20966
|
+
}
|
20967
|
+
if (disableDtx) {
|
20968
|
+
audioFeatures.push(AudioTrackFeature.TF_NO_DTX);
|
20969
|
+
}
|
20970
|
+
if (isLocalAudioTrack(track) && track.hasPreConnectBuffer) {
|
20971
|
+
audioFeatures.push(AudioTrackFeature.TF_PRECONNECT_BUFFER);
|
20972
|
+
}
|
20835
20973
|
// create track publication from track
|
20836
20974
|
const req = new AddTrackRequest({
|
20837
20975
|
// get local track id for use during publishing
|
@@ -20840,12 +20978,13 @@ class LocalParticipant extends Participant {
|
|
20840
20978
|
type: Track.kindToProto(track.kind),
|
20841
20979
|
muted: track.isMuted,
|
20842
20980
|
source: Track.sourceToProto(track.source),
|
20843
|
-
disableDtx
|
20981
|
+
disableDtx,
|
20844
20982
|
encryption: this.encryptionType,
|
20845
20983
|
stereo: isStereo,
|
20846
20984
|
disableRed: this.isE2EEEnabled || !((_b = opts.red) !== null && _b !== void 0 ? _b : true),
|
20847
20985
|
stream: opts === null || opts === void 0 ? void 0 : opts.stream,
|
20848
|
-
backupCodecPolicy: opts === null || opts === void 0 ? void 0 : opts.backupCodecPolicy
|
20986
|
+
backupCodecPolicy: opts === null || opts === void 0 ? void 0 : opts.backupCodecPolicy,
|
20987
|
+
audioFeatures
|
20849
20988
|
});
|
20850
20989
|
// compute encodings and layers for video
|
20851
20990
|
let encodings;
|
@@ -21033,6 +21172,75 @@ class LocalParticipant extends Participant {
|
|
21033
21172
|
this.addTrackPublication(publication);
|
21034
21173
|
// send event for publication
|
21035
21174
|
this.emit(ParticipantEvent.LocalTrackPublished, publication);
|
21175
|
+
if (isLocalAudioTrack(track) && ti.audioFeatures.includes(AudioTrackFeature.TF_PRECONNECT_BUFFER)) {
|
21176
|
+
const stream = track.getPreConnectBuffer();
|
21177
|
+
// TODO: we're registering the listener after negotiation, so there might be a race
|
21178
|
+
this.on(ParticipantEvent.LocalTrackSubscribed, pub => {
|
21179
|
+
if (pub.trackSid === ti.sid) {
|
21180
|
+
if (!track.hasPreConnectBuffer) {
|
21181
|
+
this.log.warn('subscribe event came to late, buffer already closed', this.logContext);
|
21182
|
+
return;
|
21183
|
+
}
|
21184
|
+
this.log.debug('finished recording preconnect buffer', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21185
|
+
track.stopPreConnectBuffer();
|
21186
|
+
}
|
21187
|
+
});
|
21188
|
+
if (stream) {
|
21189
|
+
const bufferStreamPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
21190
|
+
var _a, e_2, _b, _c;
|
21191
|
+
var _d, _e;
|
21192
|
+
try {
|
21193
|
+
this.log.debug('waiting for agent', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21194
|
+
const agentActiveTimeout = setTimeout(() => {
|
21195
|
+
reject(new Error('agent not active within 10 seconds'));
|
21196
|
+
}, 10000);
|
21197
|
+
const agent = yield this.waitUntilActiveAgentPresent();
|
21198
|
+
clearTimeout(agentActiveTimeout);
|
21199
|
+
this.log.debug('sending preconnect buffer', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21200
|
+
const writer = yield this.streamBytes({
|
21201
|
+
name: 'preconnect-buffer',
|
21202
|
+
mimeType: 'audio/opus',
|
21203
|
+
topic: 'lk.agent.pre-connect-audio-buffer',
|
21204
|
+
destinationIdentities: [agent.identity],
|
21205
|
+
attributes: {
|
21206
|
+
trackId: publication.trackSid,
|
21207
|
+
sampleRate: String((_d = settings.sampleRate) !== null && _d !== void 0 ? _d : '48000'),
|
21208
|
+
channels: String((_e = settings.channelCount) !== null && _e !== void 0 ? _e : '1')
|
21209
|
+
}
|
21210
|
+
});
|
21211
|
+
try {
|
21212
|
+
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) {
|
21213
|
+
_c = stream_1_1.value;
|
21214
|
+
_f = false;
|
21215
|
+
const chunk = _c;
|
21216
|
+
yield writer.write(chunk);
|
21217
|
+
}
|
21218
|
+
} catch (e_2_1) {
|
21219
|
+
e_2 = {
|
21220
|
+
error: e_2_1
|
21221
|
+
};
|
21222
|
+
} finally {
|
21223
|
+
try {
|
21224
|
+
if (!_f && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
|
21225
|
+
} finally {
|
21226
|
+
if (e_2) throw e_2.error;
|
21227
|
+
}
|
21228
|
+
}
|
21229
|
+
yield writer.close();
|
21230
|
+
resolve();
|
21231
|
+
} catch (e) {
|
21232
|
+
reject(e);
|
21233
|
+
}
|
21234
|
+
}));
|
21235
|
+
bufferStreamPromise.then(() => {
|
21236
|
+
this.log.debug('preconnect buffer sent successfully', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
|
21237
|
+
}).catch(e => {
|
21238
|
+
this.log.error('error sending preconnect buffer', Object.assign(Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)), {
|
21239
|
+
error: e
|
21240
|
+
}));
|
21241
|
+
});
|
21242
|
+
}
|
21243
|
+
}
|
21036
21244
|
return publication;
|
21037
21245
|
});
|
21038
21246
|
}
|
@@ -21781,6 +21989,29 @@ class LocalParticipant extends Participant {
|
|
21781
21989
|
});
|
21782
21990
|
return true;
|
21783
21991
|
}
|
21992
|
+
/** @internal */
|
21993
|
+
setActiveAgent(agent) {
|
21994
|
+
var _a, _b, _c, _d;
|
21995
|
+
this.firstActiveAgent = agent;
|
21996
|
+
if (agent && !this.firstActiveAgent) {
|
21997
|
+
this.firstActiveAgent = agent;
|
21998
|
+
}
|
21999
|
+
if (agent) {
|
22000
|
+
(_b = (_a = this.activeAgentFuture) === null || _a === void 0 ? void 0 : _a.resolve) === null || _b === void 0 ? void 0 : _b.call(_a, agent);
|
22001
|
+
} else {
|
22002
|
+
(_d = (_c = this.activeAgentFuture) === null || _c === void 0 ? void 0 : _c.reject) === null || _d === void 0 ? void 0 : _d.call(_c, 'Agent disconnected');
|
22003
|
+
}
|
22004
|
+
this.activeAgentFuture = undefined;
|
22005
|
+
}
|
22006
|
+
waitUntilActiveAgentPresent() {
|
22007
|
+
if (this.firstActiveAgent) {
|
22008
|
+
return Promise.resolve(this.firstActiveAgent);
|
22009
|
+
}
|
22010
|
+
if (!this.activeAgentFuture) {
|
22011
|
+
this.activeAgentFuture = new Future();
|
22012
|
+
}
|
22013
|
+
return this.activeAgentFuture.promise;
|
22014
|
+
}
|
21784
22015
|
getPublicationForTrack(track) {
|
21785
22016
|
let publication;
|
21786
22017
|
this.trackPublications.forEach(pub => {
|
@@ -22974,51 +23205,10 @@ class Room extends eventsExports.EventEmitter {
|
|
22974
23205
|
}
|
22975
23206
|
};
|
22976
23207
|
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
|
-
}
|
23208
|
+
var _a;
|
23209
|
+
if (((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.os) !== 'iOS') {
|
23210
|
+
// default devices are non deterministic on iOS, so we don't attempt to select them here
|
23211
|
+
yield this.selectDefaultDevices();
|
23022
23212
|
}
|
23023
23213
|
this.emit(RoomEvent.MediaDevicesChanged);
|
23024
23214
|
});
|
@@ -23923,6 +24113,59 @@ class Room extends eventsExports.EventEmitter {
|
|
23923
24113
|
}
|
23924
24114
|
}
|
23925
24115
|
}
|
24116
|
+
/**
|
24117
|
+
* attempt to select the default devices if the previously selected devices are no longer available after a device change event
|
24118
|
+
*/
|
24119
|
+
selectDefaultDevices() {
|
24120
|
+
return __awaiter(this, void 0, void 0, function* () {
|
24121
|
+
var _a, _b, _c;
|
24122
|
+
const previousDevices = DeviceManager.getInstance().previousDevices;
|
24123
|
+
// check for available devices, but don't request permissions in order to avoid prompts for kinds that haven't been used before
|
24124
|
+
const availableDevices = yield DeviceManager.getInstance().getDevices(undefined, false);
|
24125
|
+
const browser = getBrowser();
|
24126
|
+
if ((browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && browser.os !== 'iOS') {
|
24127
|
+
for (let availableDevice of availableDevices) {
|
24128
|
+
const previousDevice = previousDevices.find(info => info.deviceId === availableDevice.deviceId);
|
24129
|
+
if (previousDevice && previousDevice.label !== '' && previousDevice.kind === availableDevice.kind && previousDevice.label !== availableDevice.label) {
|
24130
|
+
// label has changed on device the same deviceId, indicating that the default device has changed on the OS level
|
24131
|
+
if (this.getActiveDevice(availableDevice.kind) === 'default') {
|
24132
|
+
// emit an active device change event only if the selected output device is actually on `default`
|
24133
|
+
this.emit(RoomEvent.ActiveDeviceChanged, availableDevice.kind, availableDevice.deviceId);
|
24134
|
+
}
|
24135
|
+
}
|
24136
|
+
}
|
24137
|
+
}
|
24138
|
+
const kinds = ['audiooutput', 'audioinput', 'videoinput'];
|
24139
|
+
for (let kind of kinds) {
|
24140
|
+
const targetSource = kindToSource(kind);
|
24141
|
+
const targetPublication = this.localParticipant.getTrackPublication(targetSource);
|
24142
|
+
if (targetPublication && ((_a = targetPublication.track) === null || _a === void 0 ? void 0 : _a.isUserProvided)) {
|
24143
|
+
// if the track is user provided, we don't want to switch devices on behalf of the user
|
24144
|
+
continue;
|
24145
|
+
}
|
24146
|
+
const devicesOfKind = availableDevices.filter(d => d.kind === kind);
|
24147
|
+
const activeDevice = this.getActiveDevice(kind);
|
24148
|
+
if (activeDevice === ((_b = previousDevices.filter(info => info.kind === kind)[0]) === null || _b === void 0 ? void 0 : _b.deviceId)) {
|
24149
|
+
// 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
|
24150
|
+
// 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
|
24151
|
+
if (devicesOfKind.length > 0 && ((_c = devicesOfKind[0]) === null || _c === void 0 ? void 0 : _c.deviceId) !== activeDevice) {
|
24152
|
+
yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
|
24153
|
+
continue;
|
24154
|
+
}
|
24155
|
+
}
|
24156
|
+
if (kind === 'audioinput' && !isSafariBased() || kind === 'videoinput') {
|
24157
|
+
// airpods on Safari need special handling for audioinput as the track doesn't end as soon as you take them out
|
24158
|
+
continue;
|
24159
|
+
}
|
24160
|
+
// switch to first available device if previously active device is not available any more
|
24161
|
+
if (devicesOfKind.length > 0 && !devicesOfKind.find(deviceInfo => deviceInfo.deviceId === this.getActiveDevice(kind)) && (
|
24162
|
+
// avoid switching audio output on safari without explicit user action as it leads to slowed down audio playback
|
24163
|
+
kind !== 'audiooutput' || !isSafariBased())) {
|
24164
|
+
yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
|
24165
|
+
}
|
24166
|
+
}
|
24167
|
+
});
|
24168
|
+
}
|
23926
24169
|
acquireAudioContext() {
|
23927
24170
|
return __awaiter(this, void 0, void 0, function* () {
|
23928
24171
|
var _a, _b;
|
@@ -24036,6 +24279,9 @@ class Room extends eventsExports.EventEmitter {
|
|
24036
24279
|
this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant);
|
24037
24280
|
}).on(ParticipantEvent.Active, () => {
|
24038
24281
|
this.emitWhenConnected(RoomEvent.ParticipantActive, participant);
|
24282
|
+
if (participant.kind === ParticipantInfo_Kind.AGENT) {
|
24283
|
+
this.localParticipant.setActiveAgent(participant);
|
24284
|
+
}
|
24039
24285
|
});
|
24040
24286
|
// update info at the end after callbacks have been set up
|
24041
24287
|
if (info) {
|
@@ -25091,5 +25337,5 @@ function isFacingModeValue(item) {
|
|
25091
25337
|
return item === undefined || allowedValues.includes(item);
|
25092
25338
|
}
|
25093
25339
|
|
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 };
|
25340
|
+
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
25341
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|