@stream-io/video-client 1.6.0-rc.0 → 1.6.0-rc2.0
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/CHANGELOG.md +219 -6
- package/dist/index.browser.es.js +286 -318
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +286 -318
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +286 -318
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +1 -2
- package/dist/src/StreamSfuClient.d.ts +2 -2
- package/dist/src/StreamVideoClient.d.ts +6 -1
- package/dist/src/coordinator/connection/client.d.ts +0 -2
- package/dist/src/coordinator/connection/types.d.ts +2 -0
- package/dist/src/gen/coordinator/index.d.ts +280 -62
- package/dist/src/helpers/sdp-munging.d.ts +0 -21
- package/dist/src/rtc/Publisher.d.ts +0 -7
- package/dist/src/rtc/Subscriber.d.ts +0 -7
- package/dist/src/store/CallState.d.ts +3 -46
- package/dist/src/store/CallingState.d.ts +46 -0
- package/dist/src/store/index.d.ts +1 -0
- package/dist/src/store/stateStore.d.ts +0 -17
- package/package.json +1 -1
- package/src/Call.ts +56 -62
- package/src/StreamSfuClient.ts +16 -12
- package/src/StreamVideoClient.ts +7 -2
- package/src/coordinator/connection/client.ts +6 -30
- package/src/coordinator/connection/types.ts +2 -0
- package/src/devices/InputMediaDeviceManager.ts +0 -2
- package/src/gen/coordinator/index.ts +283 -63
- package/src/helpers/__tests__/sdp-munging.test.ts +1 -267
- package/src/helpers/sdp-munging.ts +0 -95
- package/src/rtc/Publisher.ts +6 -18
- package/src/rtc/Subscriber.ts +0 -14
- package/src/store/CallState.ts +40 -74
- package/src/store/CallingState.ts +55 -0
- package/src/store/__tests__/CallState.test.ts +82 -7
- package/src/store/index.ts +1 -0
- package/src/store/stateStore.ts +5 -24
package/dist/index.browser.es.js
CHANGED
|
@@ -7313,6 +7313,169 @@ var rxUtils = /*#__PURE__*/Object.freeze({
|
|
|
7313
7313
|
setCurrentValue: setCurrentValue
|
|
7314
7314
|
});
|
|
7315
7315
|
|
|
7316
|
+
/**
|
|
7317
|
+
* Represents the state of the current call.
|
|
7318
|
+
*/
|
|
7319
|
+
var CallingState;
|
|
7320
|
+
(function (CallingState) {
|
|
7321
|
+
/**
|
|
7322
|
+
* The call is in an unknown state.
|
|
7323
|
+
*/
|
|
7324
|
+
CallingState["UNKNOWN"] = "unknown";
|
|
7325
|
+
/**
|
|
7326
|
+
* The call is in an idle state.
|
|
7327
|
+
*/
|
|
7328
|
+
CallingState["IDLE"] = "idle";
|
|
7329
|
+
/**
|
|
7330
|
+
* The call is in the process of ringing.
|
|
7331
|
+
* (User hasn't accepted nor rejected the call yet.)
|
|
7332
|
+
*/
|
|
7333
|
+
CallingState["RINGING"] = "ringing";
|
|
7334
|
+
/**
|
|
7335
|
+
* The call is in the process of joining.
|
|
7336
|
+
*/
|
|
7337
|
+
CallingState["JOINING"] = "joining";
|
|
7338
|
+
/**
|
|
7339
|
+
* The call is currently active.
|
|
7340
|
+
*/
|
|
7341
|
+
CallingState["JOINED"] = "joined";
|
|
7342
|
+
/**
|
|
7343
|
+
* The call has been left.
|
|
7344
|
+
*/
|
|
7345
|
+
CallingState["LEFT"] = "left";
|
|
7346
|
+
/**
|
|
7347
|
+
* The call is in the process of reconnecting.
|
|
7348
|
+
*/
|
|
7349
|
+
CallingState["RECONNECTING"] = "reconnecting";
|
|
7350
|
+
/**
|
|
7351
|
+
* The call is in the process of migrating from one node to another.
|
|
7352
|
+
*/
|
|
7353
|
+
CallingState["MIGRATING"] = "migrating";
|
|
7354
|
+
/**
|
|
7355
|
+
* The call has failed to reconnect.
|
|
7356
|
+
*/
|
|
7357
|
+
CallingState["RECONNECTING_FAILED"] = "reconnecting-failed";
|
|
7358
|
+
/**
|
|
7359
|
+
* The call is in offline mode.
|
|
7360
|
+
*/
|
|
7361
|
+
CallingState["OFFLINE"] = "offline";
|
|
7362
|
+
})(CallingState || (CallingState = {}));
|
|
7363
|
+
|
|
7364
|
+
class StreamVideoWriteableStateStore {
|
|
7365
|
+
constructor() {
|
|
7366
|
+
/**
|
|
7367
|
+
* A store keeping data of a successfully connected user over WS to the coordinator server.
|
|
7368
|
+
*/
|
|
7369
|
+
this.connectedUserSubject = new BehaviorSubject(undefined);
|
|
7370
|
+
/**
|
|
7371
|
+
* A list of {@link Call} objects created/tracked by this client.
|
|
7372
|
+
*/
|
|
7373
|
+
this.callsSubject = new BehaviorSubject([]);
|
|
7374
|
+
/**
|
|
7375
|
+
* Sets the currently connected user.
|
|
7376
|
+
*
|
|
7377
|
+
* @internal
|
|
7378
|
+
* @param user the user to set as connected.
|
|
7379
|
+
*/
|
|
7380
|
+
this.setConnectedUser = (user) => {
|
|
7381
|
+
return setCurrentValue(this.connectedUserSubject, user);
|
|
7382
|
+
};
|
|
7383
|
+
/**
|
|
7384
|
+
* Sets the list of {@link Call} objects created/tracked by this client.
|
|
7385
|
+
* @param calls
|
|
7386
|
+
*/
|
|
7387
|
+
this.setCalls = (calls) => {
|
|
7388
|
+
return setCurrentValue(this.callsSubject, calls);
|
|
7389
|
+
};
|
|
7390
|
+
/**
|
|
7391
|
+
* Adds a {@link Call} object to the list of {@link Call} objects created/tracked by this client.
|
|
7392
|
+
*
|
|
7393
|
+
* @param call the call to add.
|
|
7394
|
+
*/
|
|
7395
|
+
this.registerCall = (call) => {
|
|
7396
|
+
if (!this.calls.find((c) => c.cid === call.cid)) {
|
|
7397
|
+
this.setCalls((calls) => [...calls, call]);
|
|
7398
|
+
}
|
|
7399
|
+
};
|
|
7400
|
+
/**
|
|
7401
|
+
* Removes a {@link Call} object from the list of {@link Call} objects created/tracked by this client.
|
|
7402
|
+
*
|
|
7403
|
+
* @param call the call to remove
|
|
7404
|
+
*/
|
|
7405
|
+
this.unregisterCall = (call) => {
|
|
7406
|
+
return this.setCalls((calls) => calls.filter((c) => c !== call));
|
|
7407
|
+
};
|
|
7408
|
+
/**
|
|
7409
|
+
* Finds a {@link Call} object in the list of {@link Call} objects created/tracked by this client.
|
|
7410
|
+
*
|
|
7411
|
+
* @param type the type of call to find.
|
|
7412
|
+
* @param id the id of the call to find.
|
|
7413
|
+
*/
|
|
7414
|
+
this.findCall = (type, id) => {
|
|
7415
|
+
return this.calls.find((c) => c.type === type && c.id === id);
|
|
7416
|
+
};
|
|
7417
|
+
this.connectedUserSubject.subscribe(async (user) => {
|
|
7418
|
+
// leave all calls when the user disconnects.
|
|
7419
|
+
if (!user) {
|
|
7420
|
+
const logger = getLogger(['client-state']);
|
|
7421
|
+
for (const call of this.calls) {
|
|
7422
|
+
if (call.state.callingState === CallingState.LEFT)
|
|
7423
|
+
continue;
|
|
7424
|
+
logger('info', `User disconnected, leaving call: ${call.cid}`);
|
|
7425
|
+
await call
|
|
7426
|
+
.leave({ reason: 'client.disconnectUser() called' })
|
|
7427
|
+
.catch((err) => {
|
|
7428
|
+
logger('error', `Error leaving call: ${call.cid}`, err);
|
|
7429
|
+
});
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
});
|
|
7433
|
+
}
|
|
7434
|
+
/**
|
|
7435
|
+
* The currently connected user.
|
|
7436
|
+
*/
|
|
7437
|
+
get connectedUser() {
|
|
7438
|
+
return getCurrentValue(this.connectedUserSubject);
|
|
7439
|
+
}
|
|
7440
|
+
/**
|
|
7441
|
+
* A list of {@link Call} objects created/tracked by this client.
|
|
7442
|
+
*/
|
|
7443
|
+
get calls() {
|
|
7444
|
+
return getCurrentValue(this.callsSubject);
|
|
7445
|
+
}
|
|
7446
|
+
}
|
|
7447
|
+
/**
|
|
7448
|
+
* A reactive store that exposes state variables in a reactive manner.
|
|
7449
|
+
* You can subscribe to changes of the different state variables.
|
|
7450
|
+
* This central store contains all the state variables related to [`StreamVideoClient`](./StreamVideClient.md) and [`Call`](./Call.md).
|
|
7451
|
+
*/
|
|
7452
|
+
class StreamVideoReadOnlyStateStore {
|
|
7453
|
+
constructor(store) {
|
|
7454
|
+
/**
|
|
7455
|
+
* This method allows you the get the current value of a state variable.
|
|
7456
|
+
*
|
|
7457
|
+
* @param observable the observable to get the current value of.
|
|
7458
|
+
* @returns the current value of the observable.
|
|
7459
|
+
*/
|
|
7460
|
+
this.getCurrentValue = getCurrentValue;
|
|
7461
|
+
// convert and expose subjects as observables
|
|
7462
|
+
this.connectedUser$ = store.connectedUserSubject.asObservable();
|
|
7463
|
+
this.calls$ = store.callsSubject.asObservable();
|
|
7464
|
+
}
|
|
7465
|
+
/**
|
|
7466
|
+
* The current user connected over WS to the backend.
|
|
7467
|
+
*/
|
|
7468
|
+
get connectedUser() {
|
|
7469
|
+
return getCurrentValue(this.connectedUser$);
|
|
7470
|
+
}
|
|
7471
|
+
/**
|
|
7472
|
+
* A list of {@link Call} objects created/tracked by this client.
|
|
7473
|
+
*/
|
|
7474
|
+
get calls() {
|
|
7475
|
+
return getCurrentValue(this.calls$);
|
|
7476
|
+
}
|
|
7477
|
+
}
|
|
7478
|
+
|
|
7316
7479
|
/**
|
|
7317
7480
|
* Creates a new combined {@link Comparator<T>} which sorts items by the given comparators.
|
|
7318
7481
|
* The comparators are applied in the order they are given (left -> right).
|
|
@@ -7562,53 +7725,6 @@ const paginatedLayoutSortPreset = combineComparators(pinned, ifInvisibleOrUnknow
|
|
|
7562
7725
|
*/
|
|
7563
7726
|
const livestreamOrAudioRoomSortPreset = combineComparators(ifInvisibleBy(combineComparators(dominantSpeaker, speaking, reactionType('raised-hand'), publishingVideo, publishingAudio)), role('admin', 'host', 'speaker'));
|
|
7564
7727
|
|
|
7565
|
-
/**
|
|
7566
|
-
* Represents the state of the current call.
|
|
7567
|
-
*/
|
|
7568
|
-
var CallingState;
|
|
7569
|
-
(function (CallingState) {
|
|
7570
|
-
/**
|
|
7571
|
-
* The call is in an unknown state.
|
|
7572
|
-
*/
|
|
7573
|
-
CallingState["UNKNOWN"] = "unknown";
|
|
7574
|
-
/**
|
|
7575
|
-
* The call is in an idle state.
|
|
7576
|
-
*/
|
|
7577
|
-
CallingState["IDLE"] = "idle";
|
|
7578
|
-
/**
|
|
7579
|
-
* The call is in the process of ringing.
|
|
7580
|
-
* (User hasn't accepted nor rejected the call yet.)
|
|
7581
|
-
*/
|
|
7582
|
-
CallingState["RINGING"] = "ringing";
|
|
7583
|
-
/**
|
|
7584
|
-
* The call is in the process of joining.
|
|
7585
|
-
*/
|
|
7586
|
-
CallingState["JOINING"] = "joining";
|
|
7587
|
-
/**
|
|
7588
|
-
* The call is currently active.
|
|
7589
|
-
*/
|
|
7590
|
-
CallingState["JOINED"] = "joined";
|
|
7591
|
-
/**
|
|
7592
|
-
* The call has been left.
|
|
7593
|
-
*/
|
|
7594
|
-
CallingState["LEFT"] = "left";
|
|
7595
|
-
/**
|
|
7596
|
-
* The call is in the process of reconnecting.
|
|
7597
|
-
*/
|
|
7598
|
-
CallingState["RECONNECTING"] = "reconnecting";
|
|
7599
|
-
/**
|
|
7600
|
-
* The call is in the process of migrating from one node to another.
|
|
7601
|
-
*/
|
|
7602
|
-
CallingState["MIGRATING"] = "migrating";
|
|
7603
|
-
/**
|
|
7604
|
-
* The call has failed to reconnect.
|
|
7605
|
-
*/
|
|
7606
|
-
CallingState["RECONNECTING_FAILED"] = "reconnecting-failed";
|
|
7607
|
-
/**
|
|
7608
|
-
* The call is in offline mode.
|
|
7609
|
-
*/
|
|
7610
|
-
CallingState["OFFLINE"] = "offline";
|
|
7611
|
-
})(CallingState || (CallingState = {}));
|
|
7612
7728
|
/**
|
|
7613
7729
|
* Returns the default egress object - when no egress data is available.
|
|
7614
7730
|
*/
|
|
@@ -7958,7 +8074,8 @@ class CallState {
|
|
|
7958
8074
|
this.setCurrentValue(this.egressSubject, call.egress);
|
|
7959
8075
|
this.setCurrentValue(this.ingressSubject, call.ingress);
|
|
7960
8076
|
this.setCurrentValue(this.recordingSubject, call.recording);
|
|
7961
|
-
this.setCurrentValue(this.sessionSubject, call.session);
|
|
8077
|
+
const s = this.setCurrentValue(this.sessionSubject, call.session);
|
|
8078
|
+
this.updateParticipantCountFromSession(s);
|
|
7962
8079
|
this.setCurrentValue(this.settingsSubject, call.settings);
|
|
7963
8080
|
this.setCurrentValue(this.transcribingSubject, call.transcribing);
|
|
7964
8081
|
this.setCurrentValue(this.thumbnailsSubject, call.thumbnails);
|
|
@@ -8033,12 +8150,32 @@ class CallState {
|
|
|
8033
8150
|
},
|
|
8034
8151
|
}));
|
|
8035
8152
|
};
|
|
8153
|
+
this.updateParticipantCountFromSession = (session) => {
|
|
8154
|
+
// when in JOINED state, we should use the participant count coming through
|
|
8155
|
+
// the SFU healthcheck event, as it's more accurate.
|
|
8156
|
+
if (!session || this.callingState === CallingState.JOINED)
|
|
8157
|
+
return;
|
|
8158
|
+
const byRoleCount = Object.values(session.participants_count_by_role).reduce((total, countByRole) => total + countByRole, 0);
|
|
8159
|
+
const participantCount = Math.max(byRoleCount, session.participants.length);
|
|
8160
|
+
this.setParticipantCount(participantCount);
|
|
8161
|
+
this.setAnonymousParticipantCount(session.anonymous_participant_count || 0);
|
|
8162
|
+
};
|
|
8163
|
+
this.updateFromSessionParticipantCountUpdate = (event) => {
|
|
8164
|
+
const s = this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8165
|
+
if (!session)
|
|
8166
|
+
return session;
|
|
8167
|
+
return {
|
|
8168
|
+
...session,
|
|
8169
|
+
anonymous_participant_count: event.anonymous_participant_count,
|
|
8170
|
+
participants_count_by_role: event.participants_count_by_role,
|
|
8171
|
+
};
|
|
8172
|
+
});
|
|
8173
|
+
this.updateParticipantCountFromSession(s);
|
|
8174
|
+
};
|
|
8036
8175
|
this.updateFromSessionParticipantLeft = (event) => {
|
|
8037
|
-
this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8038
|
-
if (!session)
|
|
8039
|
-
this.logger('warn', `Received call.session_participant_left event but no session is available.`, event);
|
|
8176
|
+
const s = this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8177
|
+
if (!session)
|
|
8040
8178
|
return session;
|
|
8041
|
-
}
|
|
8042
8179
|
const { participants, participants_count_by_role } = session;
|
|
8043
8180
|
const { user, user_session_id } = event.participant;
|
|
8044
8181
|
return {
|
|
@@ -8050,13 +8187,12 @@ class CallState {
|
|
|
8050
8187
|
},
|
|
8051
8188
|
};
|
|
8052
8189
|
});
|
|
8190
|
+
this.updateParticipantCountFromSession(s);
|
|
8053
8191
|
};
|
|
8054
8192
|
this.updateFromSessionParticipantJoined = (event) => {
|
|
8055
|
-
this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8056
|
-
if (!session)
|
|
8057
|
-
this.logger('warn', `Received call.session_participant_joined event but no session is available.`, event);
|
|
8193
|
+
const s = this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8194
|
+
if (!session)
|
|
8058
8195
|
return session;
|
|
8059
|
-
}
|
|
8060
8196
|
const { participants, participants_count_by_role } = session;
|
|
8061
8197
|
const { user, user_session_id } = event.participant;
|
|
8062
8198
|
// It could happen that the backend delivers the same participant more than once.
|
|
@@ -8087,6 +8223,7 @@ class CallState {
|
|
|
8087
8223
|
},
|
|
8088
8224
|
};
|
|
8089
8225
|
});
|
|
8226
|
+
this.updateParticipantCountFromSession(s);
|
|
8090
8227
|
};
|
|
8091
8228
|
this.updateMembers = (event) => {
|
|
8092
8229
|
this.updateFromCallResponse(event.call);
|
|
@@ -8236,6 +8373,7 @@ class CallState {
|
|
|
8236
8373
|
'call.ring': (e) => this.updateFromCallResponse(e.call),
|
|
8237
8374
|
'call.missed': (e) => this.updateFromCallResponse(e.call),
|
|
8238
8375
|
'call.session_ended': (e) => this.updateFromCallResponse(e.call),
|
|
8376
|
+
'call.session_participant_count_updated': this.updateFromSessionParticipantCountUpdate,
|
|
8239
8377
|
'call.session_participant_joined': this.updateFromSessionParticipantJoined,
|
|
8240
8378
|
'call.session_participant_left': this.updateFromSessionParticipantLeft,
|
|
8241
8379
|
'call.session_started': (e) => this.updateFromCallResponse(e.call),
|
|
@@ -8431,138 +8569,6 @@ class CallState {
|
|
|
8431
8569
|
}
|
|
8432
8570
|
}
|
|
8433
8571
|
|
|
8434
|
-
class StreamVideoWriteableStateStore {
|
|
8435
|
-
constructor() {
|
|
8436
|
-
/**
|
|
8437
|
-
* A store keeping data of a successfully connected user over WS to the coordinator server.
|
|
8438
|
-
*/
|
|
8439
|
-
this.connectedUserSubject = new BehaviorSubject(undefined);
|
|
8440
|
-
/**
|
|
8441
|
-
* A list of {@link Call} objects created/tracked by this client.
|
|
8442
|
-
*/
|
|
8443
|
-
this.callsSubject = new BehaviorSubject([]);
|
|
8444
|
-
/**
|
|
8445
|
-
* Gets the current value of an observable, or undefined if the observable has
|
|
8446
|
-
* not emitted a value yet.
|
|
8447
|
-
*
|
|
8448
|
-
* @param observable$ the observable to get the value from.
|
|
8449
|
-
*/
|
|
8450
|
-
this.getCurrentValue = getCurrentValue;
|
|
8451
|
-
/**
|
|
8452
|
-
* Updates the value of the provided Subject.
|
|
8453
|
-
* An `update` can either be a new value or a function which takes
|
|
8454
|
-
* the current value and returns a new value.
|
|
8455
|
-
*
|
|
8456
|
-
* @param subject the subject to update.
|
|
8457
|
-
* @param update the update to apply to the subject.
|
|
8458
|
-
* @return the updated value.
|
|
8459
|
-
*/
|
|
8460
|
-
this.setCurrentValue = setCurrentValue;
|
|
8461
|
-
/**
|
|
8462
|
-
* Sets the currently connected user.
|
|
8463
|
-
*
|
|
8464
|
-
* @internal
|
|
8465
|
-
* @param user the user to set as connected.
|
|
8466
|
-
*/
|
|
8467
|
-
this.setConnectedUser = (user) => {
|
|
8468
|
-
return this.setCurrentValue(this.connectedUserSubject, user);
|
|
8469
|
-
};
|
|
8470
|
-
/**
|
|
8471
|
-
* Sets the list of {@link Call} objects created/tracked by this client.
|
|
8472
|
-
* @param calls
|
|
8473
|
-
*/
|
|
8474
|
-
this.setCalls = (calls) => {
|
|
8475
|
-
return this.setCurrentValue(this.callsSubject, calls);
|
|
8476
|
-
};
|
|
8477
|
-
/**
|
|
8478
|
-
* Adds a {@link Call} object to the list of {@link Call} objects created/tracked by this client.
|
|
8479
|
-
*
|
|
8480
|
-
* @param call the call to add.
|
|
8481
|
-
*/
|
|
8482
|
-
this.registerCall = (call) => {
|
|
8483
|
-
if (!this.calls.find((c) => c.cid === call.cid)) {
|
|
8484
|
-
this.setCalls((calls) => [...calls, call]);
|
|
8485
|
-
}
|
|
8486
|
-
};
|
|
8487
|
-
/**
|
|
8488
|
-
* Removes a {@link Call} object from the list of {@link Call} objects created/tracked by this client.
|
|
8489
|
-
*
|
|
8490
|
-
* @param call the call to remove
|
|
8491
|
-
*/
|
|
8492
|
-
this.unregisterCall = (call) => {
|
|
8493
|
-
return this.setCalls((calls) => calls.filter((c) => c !== call));
|
|
8494
|
-
};
|
|
8495
|
-
/**
|
|
8496
|
-
* Finds a {@link Call} object in the list of {@link Call} objects created/tracked by this client.
|
|
8497
|
-
*
|
|
8498
|
-
* @param type the type of call to find.
|
|
8499
|
-
* @param id the id of the call to find.
|
|
8500
|
-
*/
|
|
8501
|
-
this.findCall = (type, id) => {
|
|
8502
|
-
return this.calls.find((c) => c.type === type && c.id === id);
|
|
8503
|
-
};
|
|
8504
|
-
this.connectedUserSubject.subscribe(async (user) => {
|
|
8505
|
-
// leave all calls when the user disconnects.
|
|
8506
|
-
if (!user) {
|
|
8507
|
-
const logger = getLogger(['client-state']);
|
|
8508
|
-
for (const call of this.calls) {
|
|
8509
|
-
if (call.state.callingState === CallingState.LEFT)
|
|
8510
|
-
continue;
|
|
8511
|
-
logger('info', `User disconnected, leaving call: ${call.cid}`);
|
|
8512
|
-
await call
|
|
8513
|
-
.leave({ reason: 'client.disconnectUser() called' })
|
|
8514
|
-
.catch((err) => {
|
|
8515
|
-
logger('error', `Error leaving call: ${call.cid}`, err);
|
|
8516
|
-
});
|
|
8517
|
-
}
|
|
8518
|
-
}
|
|
8519
|
-
});
|
|
8520
|
-
}
|
|
8521
|
-
/**
|
|
8522
|
-
* The currently connected user.
|
|
8523
|
-
*/
|
|
8524
|
-
get connectedUser() {
|
|
8525
|
-
return this.getCurrentValue(this.connectedUserSubject);
|
|
8526
|
-
}
|
|
8527
|
-
/**
|
|
8528
|
-
* A list of {@link Call} objects created/tracked by this client.
|
|
8529
|
-
*/
|
|
8530
|
-
get calls() {
|
|
8531
|
-
return this.getCurrentValue(this.callsSubject);
|
|
8532
|
-
}
|
|
8533
|
-
}
|
|
8534
|
-
/**
|
|
8535
|
-
* A reactive store that exposes state variables in a reactive manner.
|
|
8536
|
-
* You can subscribe to changes of the different state variables.
|
|
8537
|
-
* This central store contains all the state variables related to [`StreamVideoClient`](./StreamVideClient.md) and [`Call`](./Call.md).
|
|
8538
|
-
*/
|
|
8539
|
-
class StreamVideoReadOnlyStateStore {
|
|
8540
|
-
constructor(store) {
|
|
8541
|
-
/**
|
|
8542
|
-
* This method allows you the get the current value of a state variable.
|
|
8543
|
-
*
|
|
8544
|
-
* @param observable the observable to get the current value of.
|
|
8545
|
-
* @returns the current value of the observable.
|
|
8546
|
-
*/
|
|
8547
|
-
this.getCurrentValue = getCurrentValue;
|
|
8548
|
-
// convert and expose subjects as observables
|
|
8549
|
-
this.connectedUser$ = store.connectedUserSubject.asObservable();
|
|
8550
|
-
this.calls$ = store.callsSubject.asObservable();
|
|
8551
|
-
}
|
|
8552
|
-
/**
|
|
8553
|
-
* The current user connected over WS to the backend.
|
|
8554
|
-
*/
|
|
8555
|
-
get connectedUser() {
|
|
8556
|
-
return getCurrentValue(this.connectedUser$);
|
|
8557
|
-
}
|
|
8558
|
-
/**
|
|
8559
|
-
* A list of {@link Call} objects created/tracked by this client.
|
|
8560
|
-
*/
|
|
8561
|
-
get calls() {
|
|
8562
|
-
return getCurrentValue(this.calls$);
|
|
8563
|
-
}
|
|
8564
|
-
}
|
|
8565
|
-
|
|
8566
8572
|
const getRtpMap = (line) => {
|
|
8567
8573
|
// Example: a=rtpmap:110 opus/48000/2
|
|
8568
8574
|
const rtpRegex = /^a=rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/;
|
|
@@ -8711,7 +8717,7 @@ const enableHighQualityAudio = (sdp, trackMid, maxBitrate = 510000) => {
|
|
|
8711
8717
|
return SDP.write(parsedSdp);
|
|
8712
8718
|
};
|
|
8713
8719
|
|
|
8714
|
-
const version = "1.6.0-
|
|
8720
|
+
const version = "1.6.0-rc2.0" ;
|
|
8715
8721
|
const [major, minor, patch] = version.split('.');
|
|
8716
8722
|
let sdkInfo = {
|
|
8717
8723
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -8783,16 +8789,6 @@ const getClientDetails = () => {
|
|
|
8783
8789
|
* @internal
|
|
8784
8790
|
*/
|
|
8785
8791
|
class Publisher {
|
|
8786
|
-
/**
|
|
8787
|
-
* Returns the current connection configuration.
|
|
8788
|
-
*
|
|
8789
|
-
* @internal
|
|
8790
|
-
*/
|
|
8791
|
-
get connectionConfiguration() {
|
|
8792
|
-
if (this.pc.getConfiguration)
|
|
8793
|
-
return this.pc.getConfiguration();
|
|
8794
|
-
return this._connectionConfiguration;
|
|
8795
|
-
}
|
|
8796
8792
|
/**
|
|
8797
8793
|
* Constructs a new `Publisher` instance.
|
|
8798
8794
|
*
|
|
@@ -8840,7 +8836,6 @@ class Publisher {
|
|
|
8840
8836
|
this.isIceRestarting = false;
|
|
8841
8837
|
this.createPeerConnection = (connectionConfig) => {
|
|
8842
8838
|
const pc = new RTCPeerConnection(connectionConfig);
|
|
8843
|
-
this._connectionConfiguration = connectionConfig;
|
|
8844
8839
|
pc.addEventListener('icecandidate', this.onIceCandidate);
|
|
8845
8840
|
pc.addEventListener('negotiationneeded', this.onNegotiationNeeded);
|
|
8846
8841
|
pc.addEventListener('icecandidateerror', this.onIceCandidateError);
|
|
@@ -8905,11 +8900,11 @@ class Publisher {
|
|
|
8905
8900
|
* An event handler which listens for the 'ended' event on the track.
|
|
8906
8901
|
* Once the track has ended, it will notify the SFU and update the state.
|
|
8907
8902
|
*/
|
|
8908
|
-
const handleTrackEnded =
|
|
8909
|
-
this.logger('info', `Track ${TrackType[trackType]} has ended, notifying the SFU`);
|
|
8910
|
-
|
|
8911
|
-
// clean-up, this event listener needs to run only once.
|
|
8903
|
+
const handleTrackEnded = () => {
|
|
8904
|
+
this.logger('info', `Track ${TrackType[trackType]} has ended abruptly, notifying the SFU`);
|
|
8905
|
+
// cleanup, this event listener needs to run only once.
|
|
8912
8906
|
track.removeEventListener('ended', handleTrackEnded);
|
|
8907
|
+
this.notifyTrackMuteStateChanged(mediaStream, trackType, true).catch((err) => this.logger('warn', `Couldn't notify track mute state`, err));
|
|
8913
8908
|
};
|
|
8914
8909
|
if (!transceiver) {
|
|
8915
8910
|
const { settings } = this.state;
|
|
@@ -9367,16 +9362,6 @@ class Publisher {
|
|
|
9367
9362
|
* @internal
|
|
9368
9363
|
*/
|
|
9369
9364
|
class Subscriber {
|
|
9370
|
-
/**
|
|
9371
|
-
* Returns the current connection configuration.
|
|
9372
|
-
*
|
|
9373
|
-
* @internal
|
|
9374
|
-
*/
|
|
9375
|
-
get connectionConfiguration() {
|
|
9376
|
-
if (this.pc.getConfiguration)
|
|
9377
|
-
return this.pc.getConfiguration();
|
|
9378
|
-
return this._connectionConfiguration;
|
|
9379
|
-
}
|
|
9380
9365
|
/**
|
|
9381
9366
|
* Constructs a new `Subscriber` instance.
|
|
9382
9367
|
*
|
|
@@ -9397,7 +9382,6 @@ class Subscriber {
|
|
|
9397
9382
|
*/
|
|
9398
9383
|
this.createPeerConnection = (connectionConfig) => {
|
|
9399
9384
|
const pc = new RTCPeerConnection(connectionConfig);
|
|
9400
|
-
this._connectionConfiguration = connectionConfig;
|
|
9401
9385
|
pc.addEventListener('icecandidate', this.onIceCandidate);
|
|
9402
9386
|
pc.addEventListener('track', this.handleOnTrack);
|
|
9403
9387
|
pc.addEventListener('icecandidateerror', this.onIceCandidateError);
|
|
@@ -9755,7 +9739,7 @@ class StreamSfuClient {
|
|
|
9755
9739
|
this.migrationTask?.resolve();
|
|
9756
9740
|
};
|
|
9757
9741
|
this.leaveAndClose = async (reason) => {
|
|
9758
|
-
await this.
|
|
9742
|
+
await this.joinTask;
|
|
9759
9743
|
try {
|
|
9760
9744
|
this.isLeaving = true;
|
|
9761
9745
|
await this.notifyLeave(reason);
|
|
@@ -9766,43 +9750,43 @@ class StreamSfuClient {
|
|
|
9766
9750
|
this.close(StreamSfuClient.NORMAL_CLOSURE, reason.substring(0, 115));
|
|
9767
9751
|
};
|
|
9768
9752
|
this.updateSubscriptions = async (tracks) => {
|
|
9769
|
-
await this.
|
|
9753
|
+
await this.joinTask;
|
|
9770
9754
|
return retryable(() => this.rpc.updateSubscriptions({ sessionId: this.sessionId, tracks }), this.abortController.signal);
|
|
9771
9755
|
};
|
|
9772
9756
|
this.setPublisher = async (data) => {
|
|
9773
|
-
await this.
|
|
9757
|
+
await this.joinTask;
|
|
9774
9758
|
return retryable(() => this.rpc.setPublisher({ ...data, sessionId: this.sessionId }), this.abortController.signal);
|
|
9775
9759
|
};
|
|
9776
9760
|
this.sendAnswer = async (data) => {
|
|
9777
|
-
await this.
|
|
9761
|
+
await this.joinTask;
|
|
9778
9762
|
return retryable(() => this.rpc.sendAnswer({ ...data, sessionId: this.sessionId }), this.abortController.signal);
|
|
9779
9763
|
};
|
|
9780
9764
|
this.iceTrickle = async (data) => {
|
|
9781
|
-
await this.
|
|
9765
|
+
await this.joinTask;
|
|
9782
9766
|
return retryable(() => this.rpc.iceTrickle({ ...data, sessionId: this.sessionId }), this.abortController.signal);
|
|
9783
9767
|
};
|
|
9784
9768
|
this.iceRestart = async (data) => {
|
|
9785
|
-
await this.
|
|
9769
|
+
await this.joinTask;
|
|
9786
9770
|
return retryable(() => this.rpc.iceRestart({ ...data, sessionId: this.sessionId }), this.abortController.signal);
|
|
9787
9771
|
};
|
|
9788
9772
|
this.updateMuteState = async (trackType, muted) => {
|
|
9789
|
-
await this.
|
|
9773
|
+
await this.joinTask;
|
|
9790
9774
|
return this.updateMuteStates({ muteStates: [{ trackType, muted }] });
|
|
9791
9775
|
};
|
|
9792
9776
|
this.updateMuteStates = async (data) => {
|
|
9793
|
-
await this.
|
|
9777
|
+
await this.joinTask;
|
|
9794
9778
|
return retryable(() => this.rpc.updateMuteStates({ ...data, sessionId: this.sessionId }), this.abortController.signal);
|
|
9795
9779
|
};
|
|
9796
9780
|
this.sendStats = async (stats) => {
|
|
9797
|
-
await this.
|
|
9781
|
+
await this.joinTask;
|
|
9798
9782
|
return retryable(() => this.rpc.sendStats({ ...stats, sessionId: this.sessionId }), this.abortController.signal);
|
|
9799
9783
|
};
|
|
9800
9784
|
this.startNoiseCancellation = async () => {
|
|
9801
|
-
await this.
|
|
9785
|
+
await this.joinTask;
|
|
9802
9786
|
return retryable(() => this.rpc.startNoiseCancellation({ sessionId: this.sessionId }), this.abortController.signal);
|
|
9803
9787
|
};
|
|
9804
9788
|
this.stopNoiseCancellation = async () => {
|
|
9805
|
-
await this.
|
|
9789
|
+
await this.joinTask;
|
|
9806
9790
|
return retryable(() => this.rpc.stopNoiseCancellation({ sessionId: this.sessionId }), this.abortController.signal);
|
|
9807
9791
|
};
|
|
9808
9792
|
this.enterMigration = async (opts = {}) => {
|
|
@@ -9938,6 +9922,9 @@ class StreamSfuClient {
|
|
|
9938
9922
|
get isHealthy() {
|
|
9939
9923
|
return this.signalWs.readyState === WebSocket.OPEN;
|
|
9940
9924
|
}
|
|
9925
|
+
get joinTask() {
|
|
9926
|
+
return this.joinResponseTask.promise;
|
|
9927
|
+
}
|
|
9941
9928
|
}
|
|
9942
9929
|
/**
|
|
9943
9930
|
* The normal closure code. Used for controlled shutdowns.
|
|
@@ -11874,9 +11861,6 @@ class InputMediaDeviceManager {
|
|
|
11874
11861
|
if (this.call.state.callingState === CallingState.JOINED) {
|
|
11875
11862
|
await this.publishStream(stream);
|
|
11876
11863
|
}
|
|
11877
|
-
else {
|
|
11878
|
-
this.logger('debug', 'Stream is not published as the call is not joined');
|
|
11879
|
-
}
|
|
11880
11864
|
if (this.state.mediaStream !== stream) {
|
|
11881
11865
|
this.state.setMediaStream(stream, await rootStream);
|
|
11882
11866
|
this.getTracks().forEach((track) => {
|
|
@@ -12993,7 +12977,14 @@ class Call {
|
|
|
12993
12977
|
throw new Error('Cannot leave call that has already been left.');
|
|
12994
12978
|
}
|
|
12995
12979
|
if (callingState === CallingState.JOINING) {
|
|
12996
|
-
|
|
12980
|
+
const waitUntilCallJoined = () => {
|
|
12981
|
+
return new Promise((resolve) => {
|
|
12982
|
+
this.state.callingState$
|
|
12983
|
+
.pipe(takeWhile((state) => state !== CallingState.JOINED, true))
|
|
12984
|
+
.subscribe(() => resolve());
|
|
12985
|
+
});
|
|
12986
|
+
};
|
|
12987
|
+
await waitUntilCallJoined();
|
|
12997
12988
|
}
|
|
12998
12989
|
if (this.ringing) {
|
|
12999
12990
|
// I'm the one who started the call, so I should cancel it.
|
|
@@ -13237,6 +13228,11 @@ class Call {
|
|
|
13237
13228
|
await this.applyDeviceConfig(true);
|
|
13238
13229
|
this.deviceSettingsAppliedOnce = true;
|
|
13239
13230
|
}
|
|
13231
|
+
// We shouldn't persist the `ring` state after joining the call as it's a one-time event
|
|
13232
|
+
// and clashes with the potential reconnection attempts. When reconnecting,
|
|
13233
|
+
// if provided with `ring: true`, we will spam the other participants with
|
|
13234
|
+
// push notifications and `call.ring` events.
|
|
13235
|
+
delete this.joinCallData?.ring;
|
|
13240
13236
|
this.logger('info', `Joined call ${this.cid}`);
|
|
13241
13237
|
};
|
|
13242
13238
|
/**
|
|
@@ -13296,7 +13292,7 @@ class Call {
|
|
|
13296
13292
|
dispatcher: this.dispatcher,
|
|
13297
13293
|
state: this.state,
|
|
13298
13294
|
connectionConfig,
|
|
13299
|
-
logTag: String(this.
|
|
13295
|
+
logTag: String(this.sfuClientTag),
|
|
13300
13296
|
onUnrecoverableError: () => {
|
|
13301
13297
|
this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
|
|
13302
13298
|
this.logger('warn', '[Reconnect] Error reconnecting after a subscriber error', err);
|
|
@@ -13320,7 +13316,7 @@ class Call {
|
|
|
13320
13316
|
connectionConfig,
|
|
13321
13317
|
isDtxEnabled,
|
|
13322
13318
|
isRedEnabled,
|
|
13323
|
-
logTag: String(this.
|
|
13319
|
+
logTag: String(this.sfuClientTag),
|
|
13324
13320
|
onUnrecoverableError: () => {
|
|
13325
13321
|
this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
|
|
13326
13322
|
this.logger('warn', '[Reconnect] Error reconnecting after a publisher error', err);
|
|
@@ -13373,6 +13369,21 @@ class Call {
|
|
|
13373
13369
|
}
|
|
13374
13370
|
return joinResponse;
|
|
13375
13371
|
};
|
|
13372
|
+
/**
|
|
13373
|
+
* Handles the closing of the SFU signal connection.
|
|
13374
|
+
*
|
|
13375
|
+
* @internal
|
|
13376
|
+
* @param sfuClient the SFU client instance that was closed.
|
|
13377
|
+
*/
|
|
13378
|
+
this.handleSfuSignalClose = (sfuClient) => {
|
|
13379
|
+
this.logger('debug', '[Reconnect] SFU signal connection closed');
|
|
13380
|
+
// normal close, no need to reconnect
|
|
13381
|
+
if (sfuClient.isLeaving)
|
|
13382
|
+
return;
|
|
13383
|
+
this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
|
|
13384
|
+
this.logger('warn', '[Reconnect] Error reconnecting', err);
|
|
13385
|
+
});
|
|
13386
|
+
};
|
|
13376
13387
|
/**
|
|
13377
13388
|
* Handles the reconnection flow.
|
|
13378
13389
|
*
|
|
@@ -13385,7 +13396,10 @@ class Call {
|
|
|
13385
13396
|
this.logger('info', `[Reconnect] Reconnecting with strategy ${WebsocketReconnectStrategy[strategy]}`);
|
|
13386
13397
|
this.reconnectStrategy = strategy;
|
|
13387
13398
|
do {
|
|
13388
|
-
|
|
13399
|
+
// we don't increment reconnect attempts for the FAST strategy.
|
|
13400
|
+
if (this.reconnectStrategy !== WebsocketReconnectStrategy.FAST) {
|
|
13401
|
+
this.reconnectAttempts++;
|
|
13402
|
+
}
|
|
13389
13403
|
const current = WebsocketReconnectStrategy[this.reconnectStrategy];
|
|
13390
13404
|
try {
|
|
13391
13405
|
// wait until the network is available
|
|
@@ -13411,11 +13425,17 @@ class Call {
|
|
|
13411
13425
|
break; // do-while loop, reconnection worked, exit the loop
|
|
13412
13426
|
}
|
|
13413
13427
|
catch (error) {
|
|
13414
|
-
|
|
13428
|
+
if (error instanceof ErrorFromResponse && error.unrecoverable) {
|
|
13429
|
+
this.logger('warn', `[Reconnect] Can't reconnect due to coordinator unrecoverable error`, error);
|
|
13430
|
+
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
13431
|
+
return;
|
|
13432
|
+
}
|
|
13433
|
+
this.logger('warn', `[Reconnect] ${current} (${this.reconnectAttempts}) failed. Attempting with REJOIN`, error);
|
|
13415
13434
|
await sleep(500);
|
|
13416
13435
|
this.reconnectStrategy = WebsocketReconnectStrategy.REJOIN;
|
|
13417
13436
|
}
|
|
13418
13437
|
} while (this.state.callingState !== CallingState.JOINED &&
|
|
13438
|
+
this.state.callingState !== CallingState.RECONNECTING_FAILED &&
|
|
13419
13439
|
this.state.callingState !== CallingState.LEFT);
|
|
13420
13440
|
});
|
|
13421
13441
|
};
|
|
@@ -13530,7 +13550,7 @@ class Call {
|
|
|
13530
13550
|
}
|
|
13531
13551
|
}
|
|
13532
13552
|
this.reconnect(strategy).catch((err) => {
|
|
13533
|
-
this.logger('warn', '[Reconnect] Error
|
|
13553
|
+
this.logger('warn', '[Reconnect] Error reconnecting after going online', err);
|
|
13534
13554
|
});
|
|
13535
13555
|
});
|
|
13536
13556
|
this.networkAvailableTask = networkAvailableTask;
|
|
@@ -13613,18 +13633,15 @@ class Call {
|
|
|
13613
13633
|
* @param opts the options to use when publishing the stream.
|
|
13614
13634
|
*/
|
|
13615
13635
|
this.publishVideoStream = async (videoStream, opts = {}) => {
|
|
13616
|
-
|
|
13617
|
-
// otherwise we risk breaking the ICETrickle flow.
|
|
13618
|
-
await this.waitUntilCallJoined();
|
|
13619
|
-
if (!this.publisher) {
|
|
13620
|
-
this.logger('error', 'Trying to publish video before join is completed');
|
|
13636
|
+
if (!this.sfuClient)
|
|
13621
13637
|
throw new Error(`Call not joined yet.`);
|
|
13622
|
-
|
|
13638
|
+
// joining is in progress, and we should wait until the client is ready
|
|
13639
|
+
await this.sfuClient.joinTask;
|
|
13640
|
+
if (!this.publisher)
|
|
13641
|
+
throw new Error('Publisher is not initialized');
|
|
13623
13642
|
const [videoTrack] = videoStream.getVideoTracks();
|
|
13624
|
-
if (!videoTrack)
|
|
13625
|
-
|
|
13626
|
-
return;
|
|
13627
|
-
}
|
|
13643
|
+
if (!videoTrack)
|
|
13644
|
+
throw new Error('There is no video track in the stream');
|
|
13628
13645
|
if (!this.trackPublishOrder.includes(TrackType.VIDEO)) {
|
|
13629
13646
|
this.trackPublishOrder.push(TrackType.VIDEO);
|
|
13630
13647
|
}
|
|
@@ -13640,18 +13657,15 @@ class Call {
|
|
|
13640
13657
|
* @param audioStream the audio stream to publish.
|
|
13641
13658
|
*/
|
|
13642
13659
|
this.publishAudioStream = async (audioStream) => {
|
|
13643
|
-
|
|
13644
|
-
// otherwise we risk breaking the ICETrickle flow.
|
|
13645
|
-
await this.waitUntilCallJoined();
|
|
13646
|
-
if (!this.publisher) {
|
|
13647
|
-
this.logger('error', 'Trying to publish audio before join is completed');
|
|
13660
|
+
if (!this.sfuClient)
|
|
13648
13661
|
throw new Error(`Call not joined yet.`);
|
|
13649
|
-
|
|
13662
|
+
// joining is in progress, and we should wait until the client is ready
|
|
13663
|
+
await this.sfuClient.joinTask;
|
|
13664
|
+
if (!this.publisher)
|
|
13665
|
+
throw new Error('Publisher is not initialized');
|
|
13650
13666
|
const [audioTrack] = audioStream.getAudioTracks();
|
|
13651
|
-
if (!audioTrack)
|
|
13652
|
-
|
|
13653
|
-
return;
|
|
13654
|
-
}
|
|
13667
|
+
if (!audioTrack)
|
|
13668
|
+
throw new Error('There is no audio track in the stream');
|
|
13655
13669
|
if (!this.trackPublishOrder.includes(TrackType.AUDIO)) {
|
|
13656
13670
|
this.trackPublishOrder.push(TrackType.AUDIO);
|
|
13657
13671
|
}
|
|
@@ -13667,17 +13681,15 @@ class Call {
|
|
|
13667
13681
|
* @param opts the options to use when publishing the stream.
|
|
13668
13682
|
*/
|
|
13669
13683
|
this.publishScreenShareStream = async (screenShareStream, opts = {}) => {
|
|
13670
|
-
|
|
13671
|
-
// otherwise we risk breaking the ICETrickle flow.
|
|
13672
|
-
await this.waitUntilCallJoined();
|
|
13673
|
-
if (!this.publisher) {
|
|
13674
|
-
this.logger('error', 'Trying to publish screen share before join is completed');
|
|
13684
|
+
if (!this.sfuClient)
|
|
13675
13685
|
throw new Error(`Call not joined yet.`);
|
|
13676
|
-
|
|
13686
|
+
// joining is in progress, and we should wait until the client is ready
|
|
13687
|
+
await this.sfuClient.joinTask;
|
|
13688
|
+
if (!this.publisher)
|
|
13689
|
+
throw new Error('Publisher is not initialized');
|
|
13677
13690
|
const [screenShareTrack] = screenShareStream.getVideoTracks();
|
|
13678
13691
|
if (!screenShareTrack) {
|
|
13679
|
-
|
|
13680
|
-
return;
|
|
13692
|
+
throw new Error('There is no screen share track in the stream');
|
|
13681
13693
|
}
|
|
13682
13694
|
if (!this.trackPublishOrder.includes(TrackType.SCREEN_SHARE)) {
|
|
13683
13695
|
this.trackPublishOrder.push(TrackType.SCREEN_SHARE);
|
|
@@ -13832,18 +13844,6 @@ class Call {
|
|
|
13832
13844
|
this.updatePublishQuality = async (enabledLayers) => {
|
|
13833
13845
|
return this.publisher?.updateVideoPublishQuality(enabledLayers);
|
|
13834
13846
|
};
|
|
13835
|
-
this.waitUntilCallJoined = () => {
|
|
13836
|
-
if (this.sfuClient) {
|
|
13837
|
-
// if we have an SFU client, we can wait for the join response
|
|
13838
|
-
return this.sfuClient.joinResponseTask.promise;
|
|
13839
|
-
}
|
|
13840
|
-
// otherwise, fall back to the calling state
|
|
13841
|
-
return new Promise((resolve) => {
|
|
13842
|
-
this.state.callingState$
|
|
13843
|
-
.pipe(takeWhile((state) => state !== CallingState.JOINED, true))
|
|
13844
|
-
.subscribe(() => resolve());
|
|
13845
|
-
});
|
|
13846
|
-
};
|
|
13847
13847
|
/**
|
|
13848
13848
|
* Sends a reaction to the other call participants.
|
|
13849
13849
|
*
|
|
@@ -14465,12 +14465,12 @@ class Call {
|
|
|
14465
14465
|
return;
|
|
14466
14466
|
const callSession = this.state.session;
|
|
14467
14467
|
const receiver_id = this.clientStore.connectedUser?.id;
|
|
14468
|
-
const
|
|
14468
|
+
const ended_at = callSession?.ended_at;
|
|
14469
14469
|
const created_by_id = this.state.createdBy?.id;
|
|
14470
14470
|
const rejected_by = callSession?.rejected_by;
|
|
14471
14471
|
const accepted_by = callSession?.accepted_by;
|
|
14472
14472
|
let leaveCallIdle = false;
|
|
14473
|
-
if (
|
|
14473
|
+
if (ended_at) {
|
|
14474
14474
|
// call was ended before it was accepted or rejected so we should leave it to idle
|
|
14475
14475
|
leaveCallIdle = true;
|
|
14476
14476
|
}
|
|
@@ -14498,10 +14498,10 @@ class Call {
|
|
|
14498
14498
|
}
|
|
14499
14499
|
}
|
|
14500
14500
|
else {
|
|
14501
|
-
this.scheduleAutoDrop();
|
|
14502
14501
|
if (this.state.callingState === CallingState.IDLE) {
|
|
14503
14502
|
this.state.setCallingState(CallingState.RINGING);
|
|
14504
14503
|
}
|
|
14504
|
+
this.scheduleAutoDrop();
|
|
14505
14505
|
this.leaveCallHooks.add(registerRingingCallEventHandlers(this));
|
|
14506
14506
|
}
|
|
14507
14507
|
}));
|
|
@@ -14524,21 +14524,6 @@ class Call {
|
|
|
14524
14524
|
get isCreatedByMe() {
|
|
14525
14525
|
return this.state.createdBy?.id === this.currentUserId;
|
|
14526
14526
|
}
|
|
14527
|
-
/**
|
|
14528
|
-
* Handles the closing of the SFU signal connection.
|
|
14529
|
-
*
|
|
14530
|
-
* @internal
|
|
14531
|
-
* @param sfuClient the SFU client instance that was closed.
|
|
14532
|
-
*/
|
|
14533
|
-
handleSfuSignalClose(sfuClient) {
|
|
14534
|
-
this.logger('debug', '[Reconnect] SFU signal connection closed');
|
|
14535
|
-
// normal close, no need to reconnect
|
|
14536
|
-
if (sfuClient.isLeaving)
|
|
14537
|
-
return;
|
|
14538
|
-
this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
|
|
14539
|
-
this.logger('warn', '[Reconnect] Error reconnecting', err);
|
|
14540
|
-
});
|
|
14541
|
-
}
|
|
14542
14527
|
}
|
|
14543
14528
|
|
|
14544
14529
|
var https = null;
|
|
@@ -15641,7 +15626,6 @@ class StreamClient {
|
|
|
15641
15626
|
*/
|
|
15642
15627
|
constructor(key, options) {
|
|
15643
15628
|
this.listeners = {};
|
|
15644
|
-
this.nextRequestAbortController = null;
|
|
15645
15629
|
this.devToken = (userID) => {
|
|
15646
15630
|
return DevToken(userID);
|
|
15647
15631
|
};
|
|
@@ -15772,15 +15756,6 @@ class StreamClient {
|
|
|
15772
15756
|
this.wsPromise = this.connect();
|
|
15773
15757
|
return this.wsPromise;
|
|
15774
15758
|
};
|
|
15775
|
-
this._normalizeDate = (before) => {
|
|
15776
|
-
if (before instanceof Date) {
|
|
15777
|
-
before = before.toISOString();
|
|
15778
|
-
}
|
|
15779
|
-
if (before === '') {
|
|
15780
|
-
throw new Error("Don't pass blank string for since, use null instead if resetting the token revoke");
|
|
15781
|
-
}
|
|
15782
|
-
return before;
|
|
15783
|
-
};
|
|
15784
15759
|
/**
|
|
15785
15760
|
* Disconnects the websocket and removes the user from client.
|
|
15786
15761
|
*
|
|
@@ -15957,14 +15932,13 @@ class StreamClient {
|
|
|
15957
15932
|
});
|
|
15958
15933
|
};
|
|
15959
15934
|
this.errorFromResponse = (response) => {
|
|
15960
|
-
|
|
15961
|
-
err = new ErrorFromResponse(
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
}
|
|
15935
|
+
const { data, status } = response;
|
|
15936
|
+
const err = new ErrorFromResponse();
|
|
15937
|
+
err.message = `Stream error code ${data.code}: ${data.message}`;
|
|
15938
|
+
err.code = data.code;
|
|
15939
|
+
err.unrecoverable = data.unrecoverable;
|
|
15966
15940
|
err.response = response;
|
|
15967
|
-
err.status =
|
|
15941
|
+
err.status = status;
|
|
15968
15942
|
return err;
|
|
15969
15943
|
};
|
|
15970
15944
|
this.handleResponse = (response) => {
|
|
@@ -16065,7 +16039,7 @@ class StreamClient {
|
|
|
16065
16039
|
});
|
|
16066
16040
|
};
|
|
16067
16041
|
this.getUserAgent = () => {
|
|
16068
|
-
const version = "1.6.0-
|
|
16042
|
+
const version = "1.6.0-rc2.0" ;
|
|
16069
16043
|
return (this.userAgent ||
|
|
16070
16044
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
16071
16045
|
};
|
|
@@ -16083,11 +16057,6 @@ class StreamClient {
|
|
|
16083
16057
|
}) => {
|
|
16084
16058
|
const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
|
|
16085
16059
|
const authorization = token ? { Authorization: token } : undefined;
|
|
16086
|
-
let signal = null;
|
|
16087
|
-
if (this.nextRequestAbortController !== null) {
|
|
16088
|
-
signal = this.nextRequestAbortController.signal;
|
|
16089
|
-
this.nextRequestAbortController = null;
|
|
16090
|
-
}
|
|
16091
16060
|
if (!options.headers?.['x-client-request-id']) {
|
|
16092
16061
|
options.headers = {
|
|
16093
16062
|
...options.headers,
|
|
@@ -16109,7 +16078,6 @@ class StreamClient {
|
|
|
16109
16078
|
'X-Stream-Client': this.getUserAgent(),
|
|
16110
16079
|
...options.headers,
|
|
16111
16080
|
},
|
|
16112
|
-
...(signal ? { signal } : {}),
|
|
16113
16081
|
...options.config,
|
|
16114
16082
|
...this.options.axiosRequestConfig,
|
|
16115
16083
|
};
|
|
@@ -16551,7 +16519,7 @@ class StreamVideoClient {
|
|
|
16551
16519
|
}
|
|
16552
16520
|
if (id) {
|
|
16553
16521
|
if (StreamVideoClient._instanceMap.has(apiKeyOrArgs.apiKey + id)) {
|
|
16554
|
-
this.logger('warn', `A StreamVideoClient already exists for ${user.type === 'anonymous' ? 'an
|
|
16522
|
+
this.logger('warn', `A StreamVideoClient already exists for ${user.type === 'anonymous' ? 'an anonymous user' : id}; Prefer using getOrCreateInstance method`);
|
|
16555
16523
|
}
|
|
16556
16524
|
user.id = id;
|
|
16557
16525
|
StreamVideoClient._instanceMap.set(apiKeyOrArgs.apiKey + id, this);
|