@stream-io/video-client 0.0.2-alpha.2 → 0.0.2-alpha.20
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 +97 -0
- package/dist/index.browser.es.js +226 -88
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +226 -88
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +226 -88
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +47 -23
- package/dist/src/StreamVideoClient.d.ts +1 -0
- package/dist/src/events/callEventHandlers.d.ts +12 -0
- package/dist/src/gen/coordinator/index.d.ts +60 -76
- package/dist/src/helpers/sound-detector.d.ts +10 -1
- package/dist/src/rtc/flows/join.d.ts +1 -0
- package/dist/src/store/CallState.d.ts +22 -1
- package/dist/src/store/stateStore.d.ts +7 -0
- package/dist/src/types.d.ts +7 -1
- package/package.json +1 -1
- package/src/Call.ts +147 -80
- package/src/StreamVideoClient.ts +76 -41
- package/src/events/__tests__/call-permissions.test.ts +4 -8
- package/src/events/__tests__/call.test.ts +127 -15
- package/src/events/__tests__/sessions.test.ts +0 -2
- package/src/events/call-permissions.ts +3 -11
- package/src/events/call.ts +31 -8
- package/src/events/callEventHandlers.ts +17 -7
- package/src/events/sessions.ts +2 -12
- package/src/gen/coordinator/index.ts +60 -74
- package/src/helpers/sound-detector.ts +13 -9
- package/src/rtc/flows/join.ts +7 -1
- package/src/rtc/publisher.ts +7 -6
- package/src/store/CallState.ts +31 -0
- package/src/store/stateStore.ts +10 -0
- package/src/types.ts +8 -0
package/src/Call.ts
CHANGED
|
@@ -21,11 +21,10 @@ import {
|
|
|
21
21
|
} from './store';
|
|
22
22
|
import { createSubscription, getCurrentValue } from './store/rxUtils';
|
|
23
23
|
import {
|
|
24
|
+
AcceptCallResponse,
|
|
24
25
|
BlockUserRequest,
|
|
25
26
|
BlockUserResponse,
|
|
26
27
|
EndCallResponse,
|
|
27
|
-
GetCallEdgeServerRequest,
|
|
28
|
-
GetCallEdgeServerResponse,
|
|
29
28
|
GetCallResponse,
|
|
30
29
|
GetOrCreateCallRequest,
|
|
31
30
|
GetOrCreateCallResponse,
|
|
@@ -35,6 +34,8 @@ import {
|
|
|
35
34
|
MuteUsersResponse,
|
|
36
35
|
OwnCapability,
|
|
37
36
|
QueryMembersRequest,
|
|
37
|
+
QueryMembersResponse,
|
|
38
|
+
RejectCallResponse,
|
|
38
39
|
RequestPermissionRequest,
|
|
39
40
|
RequestPermissionResponse,
|
|
40
41
|
SendEventRequest,
|
|
@@ -42,7 +43,11 @@ import {
|
|
|
42
43
|
SendReactionRequest,
|
|
43
44
|
SendReactionResponse,
|
|
44
45
|
SFUResponse,
|
|
46
|
+
StartBroadcastingResponse,
|
|
47
|
+
StartRecordingResponse,
|
|
48
|
+
StopBroadcastingResponse,
|
|
45
49
|
StopLiveResponse,
|
|
50
|
+
StopRecordingResponse,
|
|
46
51
|
UnblockUserRequest,
|
|
47
52
|
UnblockUserResponse,
|
|
48
53
|
UpdateCallMembersRequest,
|
|
@@ -191,6 +196,7 @@ export class Call {
|
|
|
191
196
|
streamClient,
|
|
192
197
|
metadata,
|
|
193
198
|
members,
|
|
199
|
+
ownCapabilities,
|
|
194
200
|
sortParticipantsBy,
|
|
195
201
|
clientStore,
|
|
196
202
|
ringing = false,
|
|
@@ -214,6 +220,7 @@ export class Call {
|
|
|
214
220
|
|
|
215
221
|
this.state.setMetadata(metadata);
|
|
216
222
|
this.state.setMembers(members || []);
|
|
223
|
+
this.state.setOwnCapabilities(ownCapabilities || []);
|
|
217
224
|
this.state.setCallingState(
|
|
218
225
|
ringing ? CallingState.RINGING : CallingState.IDLE,
|
|
219
226
|
);
|
|
@@ -239,25 +246,15 @@ export class Call {
|
|
|
239
246
|
// handles updating the permissions context when the metadata changes.
|
|
240
247
|
createSubscription(this.state.metadata$, (metadata) => {
|
|
241
248
|
if (!metadata) return;
|
|
242
|
-
this.permissionsContext.setPermissions(metadata.own_capabilities);
|
|
243
249
|
this.permissionsContext.setCallSettings(metadata.settings);
|
|
244
250
|
}),
|
|
245
251
|
|
|
246
|
-
//
|
|
247
|
-
createSubscription(this.state.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (
|
|
251
|
-
currentUserId &&
|
|
252
|
-
metadata.blocked_user_ids.includes(currentUserId)
|
|
253
|
-
) {
|
|
254
|
-
await this.leave();
|
|
255
|
-
}
|
|
256
|
-
}),
|
|
252
|
+
// handle the case when the user permissions are modified.
|
|
253
|
+
createSubscription(this.state.ownCapabilities$, (ownCapabilities) => {
|
|
254
|
+
// update the permission context.
|
|
255
|
+
this.permissionsContext.setPermissions(ownCapabilities);
|
|
257
256
|
|
|
258
|
-
|
|
259
|
-
createSubscription(this.state.metadata$, (metadata) => {
|
|
260
|
-
if (!metadata) return;
|
|
257
|
+
// check if the user still has publishing permissions and stop publishing if not.
|
|
261
258
|
const permissionToTrackType = {
|
|
262
259
|
[OwnCapability.SEND_AUDIO]: TrackType.AUDIO,
|
|
263
260
|
[OwnCapability.SEND_VIDEO]: TrackType.VIDEO,
|
|
@@ -275,6 +272,18 @@ export class Call {
|
|
|
275
272
|
});
|
|
276
273
|
}),
|
|
277
274
|
|
|
275
|
+
// handles the case when the user is blocked by the call owner.
|
|
276
|
+
createSubscription(this.state.metadata$, async (metadata) => {
|
|
277
|
+
if (!metadata) return;
|
|
278
|
+
const currentUserId = this.currentUserId;
|
|
279
|
+
if (
|
|
280
|
+
currentUserId &&
|
|
281
|
+
metadata.blocked_user_ids.includes(currentUserId)
|
|
282
|
+
) {
|
|
283
|
+
await this.leave();
|
|
284
|
+
}
|
|
285
|
+
}),
|
|
286
|
+
|
|
278
287
|
// watch for auto drop cancellation
|
|
279
288
|
createSubscription(this.state.callingState$, (callingState) => {
|
|
280
289
|
if (!this.ringing) return;
|
|
@@ -368,12 +377,10 @@ export class Call {
|
|
|
368
377
|
if (this.isCreatedByMe && !hasOtherParticipants) {
|
|
369
378
|
// Signals other users that I have cancelled my call to them
|
|
370
379
|
// before they accepted it.
|
|
371
|
-
|
|
372
|
-
await this.endCall();
|
|
380
|
+
await this.reject();
|
|
373
381
|
} else if (reject && callingState === CallingState.RINGING) {
|
|
374
382
|
// Signals other users that I have rejected the incoming call.
|
|
375
|
-
|
|
376
|
-
await this.sendEvent({ type: 'call.rejected' });
|
|
383
|
+
await this.reject();
|
|
377
384
|
}
|
|
378
385
|
}
|
|
379
386
|
|
|
@@ -443,6 +450,10 @@ export class Call {
|
|
|
443
450
|
|
|
444
451
|
/**
|
|
445
452
|
* Loads the information about the call.
|
|
453
|
+
*
|
|
454
|
+
* @param params.ring if set to true, a `call.ring` event will be sent to the call members.
|
|
455
|
+
* @param params.notify if set to true, a `call.notification` event will be sent to the call members.
|
|
456
|
+
* @param params.members_limit the members limit.
|
|
446
457
|
*/
|
|
447
458
|
get = async (params?: {
|
|
448
459
|
ring?: boolean;
|
|
@@ -453,8 +464,14 @@ export class Call {
|
|
|
453
464
|
this.streamClientBasePath,
|
|
454
465
|
params,
|
|
455
466
|
);
|
|
467
|
+
|
|
468
|
+
if (params?.ring && !this.ringing) {
|
|
469
|
+
this.ringingSubject.next(true);
|
|
470
|
+
}
|
|
471
|
+
|
|
456
472
|
this.state.setMetadata(response.call);
|
|
457
473
|
this.state.setMembers(response.members);
|
|
474
|
+
this.state.setOwnCapabilities(response.own_capabilities);
|
|
458
475
|
|
|
459
476
|
if (this.streamClient._hasConnectionID()) {
|
|
460
477
|
this.watching = true;
|
|
@@ -475,8 +492,13 @@ export class Call {
|
|
|
475
492
|
GetOrCreateCallRequest
|
|
476
493
|
>(this.streamClientBasePath, data);
|
|
477
494
|
|
|
495
|
+
if (data?.ring && !this.ringing) {
|
|
496
|
+
this.ringingSubject.next(true);
|
|
497
|
+
}
|
|
498
|
+
|
|
478
499
|
this.state.setMetadata(response.call);
|
|
479
500
|
this.state.setMembers(response.members);
|
|
501
|
+
this.state.setOwnCapabilities(response.own_capabilities);
|
|
480
502
|
|
|
481
503
|
if (this.streamClient._hasConnectionID()) {
|
|
482
504
|
this.watching = true;
|
|
@@ -486,14 +508,48 @@ export class Call {
|
|
|
486
508
|
return response;
|
|
487
509
|
};
|
|
488
510
|
|
|
511
|
+
/**
|
|
512
|
+
* A shortcut for {@link Call.get} with `ring` parameter set to `true`.
|
|
513
|
+
* Will send a `call.ring` event to the call members.
|
|
514
|
+
*/
|
|
489
515
|
ring = async (): Promise<GetCallResponse> => {
|
|
490
516
|
return await this.get({ ring: true });
|
|
491
517
|
};
|
|
492
518
|
|
|
519
|
+
/**
|
|
520
|
+
* A shortcut for {@link Call.get} with `notify` parameter set to `true`.
|
|
521
|
+
* Will send a `call.notification` event to the call members.
|
|
522
|
+
*/
|
|
493
523
|
notify = async (): Promise<GetCallResponse> => {
|
|
494
524
|
return await this.get({ notify: true });
|
|
495
525
|
};
|
|
496
526
|
|
|
527
|
+
/**
|
|
528
|
+
* Marks the incoming call as accepted.
|
|
529
|
+
*
|
|
530
|
+
* This method should be used only for "ringing" call flows.
|
|
531
|
+
* {@link Call.join} invokes this method automatically for you when joining a call.
|
|
532
|
+
* Unless you are implementing a custom "ringing" flow, you should not use this method.
|
|
533
|
+
*/
|
|
534
|
+
accept = async () => {
|
|
535
|
+
return this.streamClient.post<AcceptCallResponse>(
|
|
536
|
+
`${this.streamClientBasePath}/accept`,
|
|
537
|
+
);
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Marks the incoming call as rejected.
|
|
542
|
+
*
|
|
543
|
+
* This method should be used only for "ringing" call flows.
|
|
544
|
+
* {@link Call.leave} invokes this method automatically for you when you leave or reject this call.
|
|
545
|
+
* Unless you are implementing a custom "ringing" flow, you should not use this method.
|
|
546
|
+
*/
|
|
547
|
+
reject = async () => {
|
|
548
|
+
return this.streamClient.post<RejectCallResponse>(
|
|
549
|
+
`${this.streamClientBasePath}/reject`,
|
|
550
|
+
);
|
|
551
|
+
};
|
|
552
|
+
|
|
497
553
|
/**
|
|
498
554
|
* Will start to watch for call related WebSocket events and initiate a call session with the server.
|
|
499
555
|
*
|
|
@@ -511,6 +567,15 @@ export class Call {
|
|
|
511
567
|
const previousCallingState = this.state.callingState;
|
|
512
568
|
this.state.setCallingState(CallingState.JOINING);
|
|
513
569
|
|
|
570
|
+
if (data?.ring && !this.ringing) {
|
|
571
|
+
this.ringingSubject.next(true);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (this.ringing && !this.isCreatedByMe) {
|
|
575
|
+
// signals other users that I have accepted the incoming call.
|
|
576
|
+
await this.accept();
|
|
577
|
+
}
|
|
578
|
+
|
|
514
579
|
let sfuServer: SFUResponse;
|
|
515
580
|
let sfuToken: string;
|
|
516
581
|
let connectionConfig: RTCConfiguration | undefined;
|
|
@@ -518,6 +583,7 @@ export class Call {
|
|
|
518
583
|
const call = await join(this.streamClient, this.type, this.id, data);
|
|
519
584
|
this.state.setMetadata(call.metadata);
|
|
520
585
|
this.state.setMembers(call.members);
|
|
586
|
+
this.state.setOwnCapabilities(call.ownCapabilities);
|
|
521
587
|
connectionConfig = call.connectionConfig;
|
|
522
588
|
sfuServer = call.sfuServer;
|
|
523
589
|
sfuToken = call.token;
|
|
@@ -752,18 +818,6 @@ export class Call {
|
|
|
752
818
|
}
|
|
753
819
|
};
|
|
754
820
|
|
|
755
|
-
/**
|
|
756
|
-
* Will update the call members.
|
|
757
|
-
*
|
|
758
|
-
* @param data the request data.
|
|
759
|
-
*/
|
|
760
|
-
updateCallMembers = async (
|
|
761
|
-
data: UpdateCallMembersRequest,
|
|
762
|
-
): Promise<UpdateCallMembersResponse> => {
|
|
763
|
-
// FIXME: OL: implement kick-users
|
|
764
|
-
return this.streamClient.post(`${this.streamClientBasePath}/members`, data);
|
|
765
|
-
};
|
|
766
|
-
|
|
767
821
|
/**
|
|
768
822
|
* Starts publishing the given video stream to the call.
|
|
769
823
|
* The stream will be stopped if the user changes an input device, or if the user leaves the call.
|
|
@@ -1118,7 +1172,7 @@ export class Call {
|
|
|
1118
1172
|
sendReaction = async (
|
|
1119
1173
|
reaction: SendReactionRequest,
|
|
1120
1174
|
): Promise<SendReactionResponse> => {
|
|
1121
|
-
return this.streamClient.post(
|
|
1175
|
+
return this.streamClient.post<SendReactionResponse, SendReactionRequest>(
|
|
1122
1176
|
`${this.streamClientBasePath}/reaction`,
|
|
1123
1177
|
reaction,
|
|
1124
1178
|
);
|
|
@@ -1220,7 +1274,7 @@ export class Call {
|
|
|
1220
1274
|
* Starts recording the call
|
|
1221
1275
|
*/
|
|
1222
1276
|
startRecording = async () => {
|
|
1223
|
-
return this.streamClient.post(
|
|
1277
|
+
return this.streamClient.post<StartRecordingResponse>(
|
|
1224
1278
|
`${this.streamClientBasePath}/start_recording`,
|
|
1225
1279
|
{},
|
|
1226
1280
|
);
|
|
@@ -1230,7 +1284,7 @@ export class Call {
|
|
|
1230
1284
|
* Stops recording the call
|
|
1231
1285
|
*/
|
|
1232
1286
|
stopRecording = async () => {
|
|
1233
|
-
return this.streamClient.post(
|
|
1287
|
+
return this.streamClient.post<StopRecordingResponse>(
|
|
1234
1288
|
`${this.streamClientBasePath}/stop_recording`,
|
|
1235
1289
|
{},
|
|
1236
1290
|
);
|
|
@@ -1251,10 +1305,10 @@ export class Call {
|
|
|
1251
1305
|
`You are not allowed to request permissions: ${permissions.join(', ')}`,
|
|
1252
1306
|
);
|
|
1253
1307
|
}
|
|
1254
|
-
return this.streamClient.post
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
);
|
|
1308
|
+
return this.streamClient.post<
|
|
1309
|
+
RequestPermissionResponse,
|
|
1310
|
+
RequestPermissionRequest
|
|
1311
|
+
>(`${this.streamClientBasePath}/request_permission`, data);
|
|
1258
1312
|
};
|
|
1259
1313
|
|
|
1260
1314
|
/**
|
|
@@ -1336,7 +1390,7 @@ export class Call {
|
|
|
1336
1390
|
* Starts the broadcasting of the call.
|
|
1337
1391
|
*/
|
|
1338
1392
|
startBroadcasting = async () => {
|
|
1339
|
-
return this.streamClient.post(
|
|
1393
|
+
return this.streamClient.post<StartBroadcastingResponse>(
|
|
1340
1394
|
`${this.streamClientBasePath}/start_broadcasting`,
|
|
1341
1395
|
{},
|
|
1342
1396
|
);
|
|
@@ -1346,7 +1400,7 @@ export class Call {
|
|
|
1346
1400
|
* Stops the broadcasting of the call.
|
|
1347
1401
|
*/
|
|
1348
1402
|
stopBroadcasting = async () => {
|
|
1349
|
-
return this.streamClient.post(
|
|
1403
|
+
return this.streamClient.post<StopBroadcastingResponse>(
|
|
1350
1404
|
`${this.streamClientBasePath}/stop_broadcasting`,
|
|
1351
1405
|
{},
|
|
1352
1406
|
);
|
|
@@ -1358,10 +1412,17 @@ export class Call {
|
|
|
1358
1412
|
* @param updates the updates to apply to the call.
|
|
1359
1413
|
*/
|
|
1360
1414
|
update = async (updates: UpdateCallRequest) => {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
);
|
|
1415
|
+
const response = await this.streamClient.patch<
|
|
1416
|
+
UpdateCallResponse,
|
|
1417
|
+
UpdateCallRequest
|
|
1418
|
+
>(`${this.streamClientBasePath}`, updates);
|
|
1419
|
+
|
|
1420
|
+
const { call, members, own_capabilities } = response;
|
|
1421
|
+
this.state.setMetadata(call);
|
|
1422
|
+
this.state.setMembers(members);
|
|
1423
|
+
this.state.setOwnCapabilities(own_capabilities);
|
|
1424
|
+
|
|
1425
|
+
return response;
|
|
1365
1426
|
};
|
|
1366
1427
|
|
|
1367
1428
|
/**
|
|
@@ -1391,14 +1452,32 @@ export class Call {
|
|
|
1391
1452
|
* @returns
|
|
1392
1453
|
*/
|
|
1393
1454
|
queryMembers = (request: Omit<QueryMembersRequest, 'type' | 'id'>) => {
|
|
1394
|
-
return this.streamClient.post<QueryMembersRequest>(
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1455
|
+
return this.streamClient.post<QueryMembersResponse, QueryMembersRequest>(
|
|
1456
|
+
'/call/members',
|
|
1457
|
+
{
|
|
1458
|
+
...request,
|
|
1459
|
+
id: this.id,
|
|
1460
|
+
type: this.type,
|
|
1461
|
+
},
|
|
1462
|
+
);
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* Will update the call members.
|
|
1467
|
+
*
|
|
1468
|
+
* @param data the request data.
|
|
1469
|
+
*/
|
|
1470
|
+
updateCallMembers = async (
|
|
1471
|
+
data: UpdateCallMembersRequest,
|
|
1472
|
+
): Promise<UpdateCallMembersResponse> => {
|
|
1473
|
+
return this.streamClient.post<
|
|
1474
|
+
UpdateCallMembersResponse,
|
|
1475
|
+
UpdateCallMembersRequest
|
|
1476
|
+
>(`${this.streamClientBasePath}/members`, data);
|
|
1399
1477
|
};
|
|
1400
1478
|
|
|
1401
1479
|
private scheduleAutoDrop = () => {
|
|
1480
|
+
if (this.dropTimeout) clearTimeout(this.dropTimeout);
|
|
1402
1481
|
const subscription = this.state.metadata$
|
|
1403
1482
|
.pipe(
|
|
1404
1483
|
pairwise(),
|
|
@@ -1414,8 +1493,8 @@ export class Call {
|
|
|
1414
1493
|
currentMeta.settings.ring.auto_cancel_timeout_ms,
|
|
1415
1494
|
]
|
|
1416
1495
|
: [
|
|
1417
|
-
prevMeta?.settings.ring.
|
|
1418
|
-
currentMeta.settings.ring.
|
|
1496
|
+
prevMeta?.settings.ring.incoming_call_timeout_ms,
|
|
1497
|
+
currentMeta.settings.ring.incoming_call_timeout_ms,
|
|
1419
1498
|
];
|
|
1420
1499
|
if (typeof timeoutMs === 'undefined' || timeoutMs === prevTimeoutMs)
|
|
1421
1500
|
return;
|
|
@@ -1435,14 +1514,23 @@ export class Call {
|
|
|
1435
1514
|
};
|
|
1436
1515
|
|
|
1437
1516
|
/**
|
|
1438
|
-
*
|
|
1439
|
-
* Updates the call state with
|
|
1517
|
+
* Retrieves the list of recordings for the current call or call session.
|
|
1518
|
+
* Updates the call state with the returned array of CallRecording objects.
|
|
1519
|
+
*
|
|
1520
|
+
* If `callSessionId` is provided, it will return the recordings for that call session.
|
|
1521
|
+
* Otherwise, all recordings for the current call will be returned.
|
|
1522
|
+
*
|
|
1523
|
+
* @param callSessionId the call session id to retrieve recordings for.
|
|
1440
1524
|
*/
|
|
1441
|
-
queryRecordings = async (
|
|
1442
|
-
|
|
1443
|
-
|
|
1525
|
+
queryRecordings = async (
|
|
1526
|
+
callSessionId?: string,
|
|
1527
|
+
): Promise<ListRecordingsResponse> => {
|
|
1528
|
+
let endpoint = this.streamClientBasePath;
|
|
1529
|
+
if (callSessionId) {
|
|
1530
|
+
endpoint = `${endpoint}/${callSessionId}`;
|
|
1531
|
+
}
|
|
1444
1532
|
const response = await this.streamClient.get<ListRecordingsResponse>(
|
|
1445
|
-
`${
|
|
1533
|
+
`${endpoint}/recordings`,
|
|
1446
1534
|
);
|
|
1447
1535
|
|
|
1448
1536
|
this.state.setCallRecordingsList(response.recordings);
|
|
@@ -1450,19 +1538,6 @@ export class Call {
|
|
|
1450
1538
|
return response;
|
|
1451
1539
|
};
|
|
1452
1540
|
|
|
1453
|
-
/**
|
|
1454
|
-
* Returns a list of Edge Serves for current call.
|
|
1455
|
-
*
|
|
1456
|
-
* @deprecated merged with `call.join`.
|
|
1457
|
-
* @param data the data.
|
|
1458
|
-
*/
|
|
1459
|
-
getEdgeServer = (data: GetCallEdgeServerRequest) => {
|
|
1460
|
-
return this.streamClient.post<GetCallEdgeServerResponse>(
|
|
1461
|
-
`${this.streamClientBasePath}/get_edge_server`,
|
|
1462
|
-
data,
|
|
1463
|
-
);
|
|
1464
|
-
};
|
|
1465
|
-
|
|
1466
1541
|
/**
|
|
1467
1542
|
* Sends an event to all call participants.
|
|
1468
1543
|
*
|
|
@@ -1476,12 +1551,4 @@ export class Call {
|
|
|
1476
1551
|
event,
|
|
1477
1552
|
);
|
|
1478
1553
|
};
|
|
1479
|
-
|
|
1480
|
-
accept = async () => {
|
|
1481
|
-
return this.streamClient.post(`${this.streamClientBasePath}/accept`);
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
|
-
reject = async () => {
|
|
1485
|
-
return this.streamClient.post(`${this.streamClientBasePath}/reject`);
|
|
1486
|
-
};
|
|
1487
1554
|
}
|
package/src/StreamVideoClient.ts
CHANGED
|
@@ -24,7 +24,6 @@ import type {
|
|
|
24
24
|
EventHandler,
|
|
25
25
|
EventTypes,
|
|
26
26
|
StreamClientOptions,
|
|
27
|
-
StreamVideoEvent,
|
|
28
27
|
TokenOrProvider,
|
|
29
28
|
User,
|
|
30
29
|
} from './coordinator/connection/types';
|
|
@@ -40,6 +39,8 @@ export class StreamVideoClient {
|
|
|
40
39
|
private readonly writeableStateStore: StreamVideoWriteableStateStore;
|
|
41
40
|
streamClient: StreamClient;
|
|
42
41
|
|
|
42
|
+
private eventHandlersToUnregister: Array<() => void> = [];
|
|
43
|
+
|
|
43
44
|
/**
|
|
44
45
|
* You should create only one instance of `StreamVideoClient`.
|
|
45
46
|
* @param apiKey your Stream API key
|
|
@@ -73,52 +74,83 @@ export class StreamVideoClient {
|
|
|
73
74
|
user,
|
|
74
75
|
tokenOrProvider,
|
|
75
76
|
);
|
|
77
|
+
this.writeableStateStore.setConnectedUser(user);
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
this.eventHandlersToUnregister.push(
|
|
80
|
+
this.on('connection.changed', (e) => {
|
|
81
|
+
const event = e as ConnectionChangedEvent;
|
|
82
|
+
if (event.online) {
|
|
83
|
+
const callsToReWatch = this.writeableStateStore.calls
|
|
84
|
+
.filter((call) => call.watching)
|
|
85
|
+
.map((call) => call.cid);
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
if (callsToReWatch.length > 0) {
|
|
88
|
+
this.queryCalls({
|
|
89
|
+
watch: true,
|
|
90
|
+
filter_conditions: {
|
|
91
|
+
cid: { $in: callsToReWatch },
|
|
92
|
+
},
|
|
93
|
+
sort: [{ field: 'cid', direction: 1 }],
|
|
94
|
+
}).catch((err) => {
|
|
95
|
+
console.warn('Failed to re-watch calls', err);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
95
98
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
this.eventHandlersToUnregister.push(
|
|
103
|
+
this.on('call.created', (event) => {
|
|
104
|
+
if (event.type !== 'call.created') return;
|
|
105
|
+
const { call, members } = event;
|
|
106
|
+
if (user.id === call.created_by.id) {
|
|
107
|
+
console.warn('Received `call.created` sent by the current user');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
)
|
|
119
|
-
|
|
111
|
+
this.writeableStateStore.registerCall(
|
|
112
|
+
new Call({
|
|
113
|
+
streamClient: this.streamClient,
|
|
114
|
+
type: call.type,
|
|
115
|
+
id: call.id,
|
|
116
|
+
metadata: call,
|
|
117
|
+
members,
|
|
118
|
+
clientStore: this.writeableStateStore,
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
120
123
|
|
|
121
|
-
this.
|
|
124
|
+
this.eventHandlersToUnregister.push(
|
|
125
|
+
this.on('call.ring', async (event) => {
|
|
126
|
+
if (event.type !== 'call.ring') return;
|
|
127
|
+
const { call, members } = event;
|
|
128
|
+
if (user.id === call.created_by.id) {
|
|
129
|
+
console.warn('Received `call.ring` sent by the current user');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// The call might already be tracked by the client,
|
|
134
|
+
// if `call.created` was received before `call.ring`.
|
|
135
|
+
// In that case, we just reuse the already tracked call.
|
|
136
|
+
let theCall = this.writeableStateStore.findCall(call.type, call.id);
|
|
137
|
+
if (!theCall) {
|
|
138
|
+
// otherwise, we create a new call
|
|
139
|
+
theCall = new Call({
|
|
140
|
+
streamClient: this.streamClient,
|
|
141
|
+
type: call.type,
|
|
142
|
+
id: call.id,
|
|
143
|
+
members,
|
|
144
|
+
clientStore: this.writeableStateStore,
|
|
145
|
+
ringing: true,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// we fetch the latest metadata for the call from the server
|
|
150
|
+
await theCall.get({ ring: true });
|
|
151
|
+
this.writeableStateStore.registerCall(theCall);
|
|
152
|
+
}),
|
|
153
|
+
);
|
|
122
154
|
|
|
123
155
|
return connectUserResponse;
|
|
124
156
|
};
|
|
@@ -147,6 +179,8 @@ export class StreamVideoClient {
|
|
|
147
179
|
*/
|
|
148
180
|
disconnectUser = async (timeout?: number) => {
|
|
149
181
|
await this.streamClient.disconnectUser(timeout);
|
|
182
|
+
this.eventHandlersToUnregister.forEach((unregister) => unregister());
|
|
183
|
+
this.eventHandlersToUnregister = [];
|
|
150
184
|
this.writeableStateStore.setConnectedUser(undefined);
|
|
151
185
|
};
|
|
152
186
|
|
|
@@ -218,6 +252,7 @@ export class StreamVideoClient {
|
|
|
218
252
|
type: c.call.type,
|
|
219
253
|
metadata: c.call,
|
|
220
254
|
members: c.members,
|
|
255
|
+
ownCapabilities: c.own_capabilities,
|
|
221
256
|
watching: data.watch,
|
|
222
257
|
clientStore: this.writeableStateStore,
|
|
223
258
|
});
|
|
@@ -42,7 +42,7 @@ describe('Call Permission Events', () => {
|
|
|
42
42
|
},
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
expect(state.
|
|
45
|
+
expect(state.ownCapabilities).toEqual([
|
|
46
46
|
OwnCapability.SEND_AUDIO,
|
|
47
47
|
OwnCapability.SEND_VIDEO,
|
|
48
48
|
]);
|
|
@@ -61,9 +61,7 @@ describe('Call Permission Events', () => {
|
|
|
61
61
|
teams: [],
|
|
62
62
|
},
|
|
63
63
|
});
|
|
64
|
-
expect(state.
|
|
65
|
-
OwnCapability.SEND_VIDEO,
|
|
66
|
-
]);
|
|
64
|
+
expect(state.ownCapabilities).toEqual([OwnCapability.SEND_VIDEO]);
|
|
67
65
|
});
|
|
68
66
|
|
|
69
67
|
it('handles sfu.callGrantsUpdated', () => {
|
|
@@ -83,7 +81,7 @@ describe('Call Permission Events', () => {
|
|
|
83
81
|
},
|
|
84
82
|
});
|
|
85
83
|
|
|
86
|
-
expect(state.
|
|
84
|
+
expect(state.ownCapabilities).toEqual([
|
|
87
85
|
OwnCapability.SEND_AUDIO,
|
|
88
86
|
OwnCapability.SEND_VIDEO,
|
|
89
87
|
OwnCapability.SCREENSHARE,
|
|
@@ -102,8 +100,6 @@ describe('Call Permission Events', () => {
|
|
|
102
100
|
},
|
|
103
101
|
},
|
|
104
102
|
});
|
|
105
|
-
expect(state.
|
|
106
|
-
OwnCapability.SEND_AUDIO,
|
|
107
|
-
]);
|
|
103
|
+
expect(state.ownCapabilities).toEqual([OwnCapability.SEND_AUDIO]);
|
|
108
104
|
});
|
|
109
105
|
});
|