@poolse/react 2.14.1 → 2.15.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 +26 -0
- package/dist/index.cjs +65 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +65 -26
- 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,22 @@ 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);
|
|
1314
1333
|
const [error, setError] = useState(null);
|
|
1334
|
+
const incomingRef = useRef(null);
|
|
1335
|
+
incomingRef.current = incoming;
|
|
1336
|
+
const outgoingRef = useRef(null);
|
|
1337
|
+
outgoingRef.current = outgoing;
|
|
1338
|
+
const activeCallIdRef = useRef(null);
|
|
1339
|
+
activeCallIdRef.current = activeCallId;
|
|
1340
|
+
const isCurrent = useCallback((callId) => {
|
|
1341
|
+
return callId === activeCallIdRef.current || callId === incomingRef.current?.callId || callId === outgoingRef.current?.callId;
|
|
1342
|
+
}, []);
|
|
1315
1343
|
const actionsRef = useRef({
|
|
1316
1344
|
cancel: async () => {
|
|
1317
1345
|
},
|
|
@@ -1322,40 +1350,45 @@ function useCalls(userId, opts = {}) {
|
|
|
1322
1350
|
useEffect(() => {
|
|
1323
1351
|
if (!calls) return;
|
|
1324
1352
|
const offIncoming = calls.onIncoming((call2) => {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
return "ringing-in";
|
|
1333
|
-
});
|
|
1353
|
+
if (phaseRef.current !== "idle") {
|
|
1354
|
+
void calls.markBusy(call2).catch(() => {
|
|
1355
|
+
});
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
setIncoming(call2);
|
|
1359
|
+
setPhase("ringing-in");
|
|
1334
1360
|
});
|
|
1335
1361
|
const offAccepted = calls.onAccepted((call2) => {
|
|
1362
|
+
if (outgoingRef.current && call2.callId !== outgoingRef.current.callId) return;
|
|
1336
1363
|
setPhase("active");
|
|
1337
1364
|
setActiveConversationId(call2.conversationId);
|
|
1365
|
+
setActiveCallId(call2.callId);
|
|
1338
1366
|
});
|
|
1339
|
-
const offDeclined = calls.onDeclined(() => {
|
|
1367
|
+
const offDeclined = calls.onDeclined((call2) => {
|
|
1368
|
+
if (!isCurrent(call2.callId)) return;
|
|
1340
1369
|
setPhase("declined");
|
|
1341
1370
|
setOutgoing(null);
|
|
1371
|
+
setActiveCallId(null);
|
|
1342
1372
|
});
|
|
1343
|
-
const offBusy = calls.onBusy(() => {
|
|
1373
|
+
const offBusy = calls.onBusy((call2) => {
|
|
1374
|
+
if (!isCurrent(call2.callId)) return;
|
|
1344
1375
|
setPhase("busy");
|
|
1345
1376
|
setOutgoing(null);
|
|
1377
|
+
setActiveCallId(null);
|
|
1346
1378
|
});
|
|
1347
|
-
const offEnded = calls.onEnded(() => {
|
|
1379
|
+
const offEnded = calls.onEnded((call2) => {
|
|
1380
|
+
if (!isCurrent(call2.callId)) return;
|
|
1348
1381
|
setPhase("idle");
|
|
1349
1382
|
setIncoming(null);
|
|
1350
1383
|
setOutgoing(null);
|
|
1351
1384
|
setActiveConversationId(null);
|
|
1385
|
+
setActiveCallId(null);
|
|
1352
1386
|
});
|
|
1353
1387
|
const offCancelled = calls.onCancelled((call2) => {
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
});
|
|
1388
|
+
if (call2.callId !== incomingRef.current?.callId) return;
|
|
1389
|
+
setIncoming(null);
|
|
1390
|
+
setPhase("idle");
|
|
1391
|
+
setActiveCallId(null);
|
|
1359
1392
|
});
|
|
1360
1393
|
return () => {
|
|
1361
1394
|
offIncoming();
|
|
@@ -1365,7 +1398,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1365
1398
|
offEnded();
|
|
1366
1399
|
offCancelled();
|
|
1367
1400
|
};
|
|
1368
|
-
}, [calls]);
|
|
1401
|
+
}, [calls, isCurrent]);
|
|
1369
1402
|
const call = useCallback(
|
|
1370
1403
|
async (conversationId, media2 = "audio") => {
|
|
1371
1404
|
if (!calls) return;
|
|
@@ -1373,6 +1406,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1373
1406
|
try {
|
|
1374
1407
|
const placed = await calls.invite(conversationId, media2);
|
|
1375
1408
|
setOutgoing(placed);
|
|
1409
|
+
setActiveCallId(placed.callId);
|
|
1376
1410
|
setPhase("ringing-out");
|
|
1377
1411
|
} catch (err) {
|
|
1378
1412
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1388,6 +1422,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1388
1422
|
try {
|
|
1389
1423
|
await calls.accept(target);
|
|
1390
1424
|
setActiveConversationId(target.conversationId);
|
|
1425
|
+
setActiveCallId(target.callId);
|
|
1391
1426
|
setPhase("active");
|
|
1392
1427
|
setIncoming(null);
|
|
1393
1428
|
} catch (err) {
|
|
@@ -1406,6 +1441,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1406
1441
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1407
1442
|
} finally {
|
|
1408
1443
|
setIncoming(null);
|
|
1444
|
+
setActiveCallId(null);
|
|
1409
1445
|
setPhase("idle");
|
|
1410
1446
|
}
|
|
1411
1447
|
},
|
|
@@ -1419,6 +1455,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1419
1455
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1420
1456
|
} finally {
|
|
1421
1457
|
setOutgoing(null);
|
|
1458
|
+
setActiveCallId(null);
|
|
1422
1459
|
setPhase("idle");
|
|
1423
1460
|
}
|
|
1424
1461
|
}, [calls, outgoing]);
|
|
@@ -1436,7 +1473,7 @@ function useCalls(userId, opts = {}) {
|
|
|
1436
1473
|
}, [phase, ringTimeoutMs]);
|
|
1437
1474
|
const hangUp = useCallback(async () => {
|
|
1438
1475
|
const conversationId = activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;
|
|
1439
|
-
const callId = incoming?.callId ?? outgoing?.callId;
|
|
1476
|
+
const callId = activeCallId ?? incoming?.callId ?? outgoing?.callId;
|
|
1440
1477
|
try {
|
|
1441
1478
|
if (!calls || !callId || !conversationId) return;
|
|
1442
1479
|
if (phase === "ringing-out" && outgoing) {
|
|
@@ -1453,13 +1490,15 @@ function useCalls(userId, opts = {}) {
|
|
|
1453
1490
|
setIncoming(null);
|
|
1454
1491
|
setOutgoing(null);
|
|
1455
1492
|
setActiveConversationId(null);
|
|
1493
|
+
setActiveCallId(null);
|
|
1456
1494
|
}
|
|
1457
|
-
}, [calls, phase, incoming, outgoing, activeConversationId]);
|
|
1495
|
+
}, [calls, phase, incoming, outgoing, activeConversationId, activeCallId]);
|
|
1458
1496
|
const reset = useCallback(() => {
|
|
1459
1497
|
setPhase("idle");
|
|
1460
1498
|
setIncoming(null);
|
|
1461
1499
|
setOutgoing(null);
|
|
1462
1500
|
setActiveConversationId(null);
|
|
1501
|
+
setActiveCallId(null);
|
|
1463
1502
|
setError(null);
|
|
1464
1503
|
}, []);
|
|
1465
1504
|
const media = incoming?.media ?? outgoing?.media ?? "audio";
|