@poolse/react 2.14.1 → 2.15.1
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 +38 -0
- package/dist/index.cjs +77 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +77 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1081,6 +1081,7 @@ function useCallRoom(conversationId, opts) {
|
|
|
1081
1081
|
const optsRef = useRef(opts);
|
|
1082
1082
|
optsRef.current = opts;
|
|
1083
1083
|
const joined = useRef(false);
|
|
1084
|
+
const held = useRef(null);
|
|
1084
1085
|
const room = useMemo(() => {
|
|
1085
1086
|
if (!conversationId) return null;
|
|
1086
1087
|
return poolse.call(conversationId, {
|
|
@@ -1120,6 +1121,7 @@ function useCallRoom(conversationId, opts) {
|
|
|
1120
1121
|
}
|
|
1121
1122
|
setStatus(room.getStatus());
|
|
1122
1123
|
setParticipants(room.getParticipants());
|
|
1124
|
+
held.current = room;
|
|
1123
1125
|
setAlone(false);
|
|
1124
1126
|
const offStatus = room.onStatus(setStatus);
|
|
1125
1127
|
const offRoster = room.onParticipants((next) => {
|
|
@@ -1135,6 +1137,7 @@ function useCallRoom(conversationId, opts) {
|
|
|
1135
1137
|
offAlone();
|
|
1136
1138
|
offDevices();
|
|
1137
1139
|
offError();
|
|
1140
|
+
held.current = null;
|
|
1138
1141
|
if (joined.current) {
|
|
1139
1142
|
joined.current = false;
|
|
1140
1143
|
room.leave();
|
|
@@ -1142,14 +1145,19 @@ function useCallRoom(conversationId, opts) {
|
|
|
1142
1145
|
};
|
|
1143
1146
|
}, [room, sync, refreshDevices]);
|
|
1144
1147
|
const join = useCallback(async () => {
|
|
1145
|
-
|
|
1148
|
+
const target = room;
|
|
1149
|
+
if (!target) return false;
|
|
1146
1150
|
setError(null);
|
|
1147
1151
|
try {
|
|
1148
|
-
const connected = await
|
|
1152
|
+
const connected = await target.join();
|
|
1153
|
+
if (held.current !== target) {
|
|
1154
|
+
if (connected) target.leave();
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1149
1157
|
joined.current = connected;
|
|
1150
1158
|
setSfuAvailable(connected);
|
|
1151
|
-
sync(
|
|
1152
|
-
if (connected) refreshDevices(
|
|
1159
|
+
sync(target);
|
|
1160
|
+
if (connected) refreshDevices(target);
|
|
1153
1161
|
return connected;
|
|
1154
1162
|
} catch (err) {
|
|
1155
1163
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1256,12 +1264,14 @@ function useVoiceRoom(conversationId, opts = {}) {
|
|
|
1256
1264
|
const [error, setError] = useState(null);
|
|
1257
1265
|
const optsRef = useRef(opts);
|
|
1258
1266
|
const joined = useRef(false);
|
|
1267
|
+
const held = useRef(null);
|
|
1259
1268
|
const room = useMemo(
|
|
1260
1269
|
() => conversationId ? poolse.realtime.voice(conversationId, optsRef.current) : null,
|
|
1261
1270
|
[poolse, conversationId]
|
|
1262
1271
|
);
|
|
1263
1272
|
useEffect(() => {
|
|
1264
1273
|
if (!room) return;
|
|
1274
|
+
held.current = room;
|
|
1265
1275
|
setStatus(room.getStatus());
|
|
1266
1276
|
setParticipants(room.getParticipants());
|
|
1267
1277
|
setMuted(room.isMuted());
|
|
@@ -1272,6 +1282,7 @@ function useVoiceRoom(conversationId, opts = {}) {
|
|
|
1272
1282
|
offStatus();
|
|
1273
1283
|
offRoster();
|
|
1274
1284
|
offError();
|
|
1285
|
+
held.current = null;
|
|
1275
1286
|
if (joined.current) {
|
|
1276
1287
|
joined.current = false;
|
|
1277
1288
|
room.leave();
|
|
@@ -1279,10 +1290,15 @@ function useVoiceRoom(conversationId, opts = {}) {
|
|
|
1279
1290
|
};
|
|
1280
1291
|
}, [room]);
|
|
1281
1292
|
const join = useCallback(async () => {
|
|
1282
|
-
|
|
1293
|
+
const target = room;
|
|
1294
|
+
if (!target) return;
|
|
1283
1295
|
setError(null);
|
|
1284
1296
|
try {
|
|
1285
|
-
await
|
|
1297
|
+
await target.join();
|
|
1298
|
+
if (held.current !== target) {
|
|
1299
|
+
target.leave();
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1286
1302
|
joined.current = true;
|
|
1287
1303
|
} catch (err) {
|
|
1288
1304
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1308,10 +1324,23 @@ function useCalls(userId, opts = {}) {
|
|
|
1308
1324
|
const ringTimeoutMs = opts.ringTimeoutMs ?? 45e3;
|
|
1309
1325
|
const poolse = usePoolse();
|
|
1310
1326
|
const [phase, setPhase] = useState("idle");
|
|
1327
|
+
const phaseRef = useRef("idle");
|
|
1328
|
+
phaseRef.current = phase;
|
|
1311
1329
|
const [incoming, setIncoming] = useState(null);
|
|
1312
1330
|
const [outgoing, setOutgoing] = useState(null);
|
|
1313
1331
|
const [activeConversationId, setActiveConversationId] = useState(null);
|
|
1332
|
+
const [activeCallId, setActiveCallId] = useState(null);
|
|
1333
|
+
const [activeMedia, setActiveMedia] = useState(null);
|
|
1314
1334
|
const [error, setError] = useState(null);
|
|
1335
|
+
const incomingRef = useRef(null);
|
|
1336
|
+
incomingRef.current = incoming;
|
|
1337
|
+
const outgoingRef = useRef(null);
|
|
1338
|
+
outgoingRef.current = outgoing;
|
|
1339
|
+
const activeCallIdRef = useRef(null);
|
|
1340
|
+
activeCallIdRef.current = activeCallId;
|
|
1341
|
+
const isCurrent = useCallback((callId) => {
|
|
1342
|
+
return callId === activeCallIdRef.current || callId === incomingRef.current?.callId || callId === outgoingRef.current?.callId;
|
|
1343
|
+
}, []);
|
|
1315
1344
|
const actionsRef = useRef({
|
|
1316
1345
|
cancel: async () => {
|
|
1317
1346
|
},
|
|
@@ -1322,40 +1351,49 @@ function useCalls(userId, opts = {}) {
|
|
|
1322
1351
|
useEffect(() => {
|
|
1323
1352
|
if (!calls) return;
|
|
1324
1353
|
const offIncoming = calls.onIncoming((call2) => {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
return "ringing-in";
|
|
1333
|
-
});
|
|
1354
|
+
if (phaseRef.current !== "idle") {
|
|
1355
|
+
void calls.markBusy(call2).catch(() => {
|
|
1356
|
+
});
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
setIncoming(call2);
|
|
1360
|
+
setPhase("ringing-in");
|
|
1334
1361
|
});
|
|
1335
1362
|
const offAccepted = calls.onAccepted((call2) => {
|
|
1363
|
+
if (outgoingRef.current && call2.callId !== outgoingRef.current.callId) return;
|
|
1336
1364
|
setPhase("active");
|
|
1337
1365
|
setActiveConversationId(call2.conversationId);
|
|
1366
|
+
setActiveCallId(call2.callId);
|
|
1338
1367
|
});
|
|
1339
|
-
const offDeclined = calls.onDeclined(() => {
|
|
1368
|
+
const offDeclined = calls.onDeclined((call2) => {
|
|
1369
|
+
if (!isCurrent(call2.callId)) return;
|
|
1340
1370
|
setPhase("declined");
|
|
1341
1371
|
setOutgoing(null);
|
|
1372
|
+
setActiveCallId(null);
|
|
1373
|
+
setActiveMedia(null);
|
|
1342
1374
|
});
|
|
1343
|
-
const offBusy = calls.onBusy(() => {
|
|
1375
|
+
const offBusy = calls.onBusy((call2) => {
|
|
1376
|
+
if (!isCurrent(call2.callId)) return;
|
|
1344
1377
|
setPhase("busy");
|
|
1345
1378
|
setOutgoing(null);
|
|
1379
|
+
setActiveCallId(null);
|
|
1380
|
+
setActiveMedia(null);
|
|
1346
1381
|
});
|
|
1347
|
-
const offEnded = calls.onEnded(() => {
|
|
1382
|
+
const offEnded = calls.onEnded((call2) => {
|
|
1383
|
+
if (!isCurrent(call2.callId)) return;
|
|
1348
1384
|
setPhase("idle");
|
|
1349
1385
|
setIncoming(null);
|
|
1350
1386
|
setOutgoing(null);
|
|
1351
1387
|
setActiveConversationId(null);
|
|
1388
|
+
setActiveCallId(null);
|
|
1389
|
+
setActiveMedia(null);
|
|
1352
1390
|
});
|
|
1353
1391
|
const offCancelled = calls.onCancelled((call2) => {
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1392
|
+
if (call2.callId !== incomingRef.current?.callId) return;
|
|
1393
|
+
setIncoming(null);
|
|
1394
|
+
setPhase("idle");
|
|
1395
|
+
setActiveCallId(null);
|
|
1396
|
+
setActiveMedia(null);
|
|
1359
1397
|
});
|
|
1360
1398
|
return () => {
|
|
1361
1399
|
offIncoming();
|
|
@@ -1365,7 +1403,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1365
1403
|
offEnded();
|
|
1366
1404
|
offCancelled();
|
|
1367
1405
|
};
|
|
1368
|
-
}, [calls]);
|
|
1406
|
+
}, [calls, isCurrent]);
|
|
1369
1407
|
const call = useCallback(
|
|
1370
1408
|
async (conversationId, media2 = "audio") => {
|
|
1371
1409
|
if (!calls) return;
|
|
@@ -1373,6 +1411,8 @@ function useCalls(userId, opts = {}) {
|
|
|
1373
1411
|
try {
|
|
1374
1412
|
const placed = await calls.invite(conversationId, media2);
|
|
1375
1413
|
setOutgoing(placed);
|
|
1414
|
+
setActiveCallId(placed.callId);
|
|
1415
|
+
setActiveMedia(placed.media);
|
|
1376
1416
|
setPhase("ringing-out");
|
|
1377
1417
|
} catch (err) {
|
|
1378
1418
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1388,6 +1428,8 @@ function useCalls(userId, opts = {}) {
|
|
|
1388
1428
|
try {
|
|
1389
1429
|
await calls.accept(target);
|
|
1390
1430
|
setActiveConversationId(target.conversationId);
|
|
1431
|
+
setActiveCallId(target.callId);
|
|
1432
|
+
setActiveMedia(target.media);
|
|
1391
1433
|
setPhase("active");
|
|
1392
1434
|
setIncoming(null);
|
|
1393
1435
|
} catch (err) {
|
|
@@ -1406,6 +1448,8 @@ function useCalls(userId, opts = {}) {
|
|
|
1406
1448
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1407
1449
|
} finally {
|
|
1408
1450
|
setIncoming(null);
|
|
1451
|
+
setActiveCallId(null);
|
|
1452
|
+
setActiveMedia(null);
|
|
1409
1453
|
setPhase("idle");
|
|
1410
1454
|
}
|
|
1411
1455
|
},
|
|
@@ -1419,6 +1463,8 @@ function useCalls(userId, opts = {}) {
|
|
|
1419
1463
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1420
1464
|
} finally {
|
|
1421
1465
|
setOutgoing(null);
|
|
1466
|
+
setActiveCallId(null);
|
|
1467
|
+
setActiveMedia(null);
|
|
1422
1468
|
setPhase("idle");
|
|
1423
1469
|
}
|
|
1424
1470
|
}, [calls, outgoing]);
|
|
@@ -1436,7 +1482,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1436
1482
|
}, [phase, ringTimeoutMs]);
|
|
1437
1483
|
const hangUp = useCallback(async () => {
|
|
1438
1484
|
const conversationId = activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;
|
|
1439
|
-
const callId = incoming?.callId ?? outgoing?.callId;
|
|
1485
|
+
const callId = activeCallId ?? incoming?.callId ?? outgoing?.callId;
|
|
1440
1486
|
try {
|
|
1441
1487
|
if (!calls || !callId || !conversationId) return;
|
|
1442
1488
|
if (phase === "ringing-out" && outgoing) {
|
|
@@ -1453,16 +1499,20 @@ function useCalls(userId, opts = {}) {
|
|
|
1453
1499
|
setIncoming(null);
|
|
1454
1500
|
setOutgoing(null);
|
|
1455
1501
|
setActiveConversationId(null);
|
|
1502
|
+
setActiveCallId(null);
|
|
1503
|
+
setActiveMedia(null);
|
|
1456
1504
|
}
|
|
1457
|
-
}, [calls, phase, incoming, outgoing, activeConversationId]);
|
|
1505
|
+
}, [calls, phase, incoming, outgoing, activeConversationId, activeCallId]);
|
|
1458
1506
|
const reset = useCallback(() => {
|
|
1459
1507
|
setPhase("idle");
|
|
1460
1508
|
setIncoming(null);
|
|
1461
1509
|
setOutgoing(null);
|
|
1462
1510
|
setActiveConversationId(null);
|
|
1511
|
+
setActiveCallId(null);
|
|
1512
|
+
setActiveMedia(null);
|
|
1463
1513
|
setError(null);
|
|
1464
1514
|
}, []);
|
|
1465
|
-
const media = incoming?.media ?? outgoing?.media ?? "audio";
|
|
1515
|
+
const media = incoming?.media ?? outgoing?.media ?? activeMedia ?? "audio";
|
|
1466
1516
|
return {
|
|
1467
1517
|
phase,
|
|
1468
1518
|
incoming,
|