realtime-avatar 0.26.1 → 0.27.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/README.md +26 -1
- package/dist/{chunk-V3PQ7RNX.js → chunk-4IEGR75H.js} +6 -1
- package/dist/{chunk-MSPXJU5P.js → chunk-DOHZ365B.js} +1 -1
- package/dist/express.d.ts +2 -2
- package/dist/express.js +2 -2
- package/dist/hono.d.ts +2 -2
- package/dist/hono.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/nextjs.d.ts +2 -2
- package/dist/nextjs.js +2 -2
- package/dist/{proxy-client-C8M_G_Kk.d.ts → proxy-client-Cs2azqD1.d.ts} +33 -6
- package/dist/react-native.d.ts +8 -3
- package/dist/react-native.js +167 -35
- package/dist/react.d.ts +7 -2
- package/dist/react.js +168 -36
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/tanstack-start.d.ts +2 -2
- package/dist/tanstack-start.js +2 -2
- package/dist/{types-D77jgSms.d.ts → types-6MUqx800.d.ts} +40 -3
- package/dist/{types-C7B7jOx6.d.ts → types-JtCwa0Ip.d.ts} +1 -1
- package/package.json +1 -1
package/dist/react-native.js
CHANGED
|
@@ -177,6 +177,8 @@ function RealtimeAvatarLiveKitRoom(props) {
|
|
|
177
177
|
LiveKitRoom,
|
|
178
178
|
{
|
|
179
179
|
...roomProps,
|
|
180
|
+
// Keep the room and its in-room observers scoped to the grant, as on web.
|
|
181
|
+
key: grant?.session_id ?? "no-session",
|
|
180
182
|
serverUrl: grant?.livekit_url,
|
|
181
183
|
token: grant?.participant_token,
|
|
182
184
|
connect: shouldConnect,
|
|
@@ -1416,6 +1418,9 @@ function useAvatarQualityGovernor(input) {
|
|
|
1416
1418
|
}
|
|
1417
1419
|
|
|
1418
1420
|
// ../client/src/react/avatar-video-surface.ts
|
|
1421
|
+
function liveBadgeLabel(dims, debug) {
|
|
1422
|
+
return debug && dims && dims.width > 0 && dims.height > 0 ? `live \xB7 ${dims.width}\xD7${dims.height}` : "live";
|
|
1423
|
+
}
|
|
1419
1424
|
function resolveSurfaceLayers(input) {
|
|
1420
1425
|
return {
|
|
1421
1426
|
showPoster: Boolean(input.poster),
|
|
@@ -1491,6 +1496,7 @@ function AvatarVideoSurface(props) {
|
|
|
1491
1496
|
style,
|
|
1492
1497
|
children,
|
|
1493
1498
|
showLiveBadge = true,
|
|
1499
|
+
debug = false,
|
|
1494
1500
|
adaptivePlayout = false,
|
|
1495
1501
|
onPlayoutDelayChange,
|
|
1496
1502
|
testID
|
|
@@ -1533,7 +1539,7 @@ function AvatarVideoSurface(props) {
|
|
|
1533
1539
|
});
|
|
1534
1540
|
const resizeMode = fit === "cover" ? "cover" : "contain";
|
|
1535
1541
|
const liveDims = videoTrack?.publication?.dimensions ?? null;
|
|
1536
|
-
const liveLabel =
|
|
1542
|
+
const liveLabel = liveBadgeLabel(liveDims, debug);
|
|
1537
1543
|
const posterLayer = layers.showPoster ? createElement(Image, {
|
|
1538
1544
|
key: "poster",
|
|
1539
1545
|
source: { uri: poster },
|
|
@@ -2391,7 +2397,8 @@ function lifecyclePhaseFrom(args) {
|
|
|
2391
2397
|
kind: "reconnectable",
|
|
2392
2398
|
reconnecting: true,
|
|
2393
2399
|
attempt: recovery.attempt,
|
|
2394
|
-
strategy: "fresh-grant"
|
|
2400
|
+
strategy: "fresh-grant",
|
|
2401
|
+
...recovery.reason ? { reason: recovery.reason } : {}
|
|
2395
2402
|
};
|
|
2396
2403
|
}
|
|
2397
2404
|
if (recovery.kind === "failed") {
|
|
@@ -2399,11 +2406,16 @@ function lifecyclePhaseFrom(args) {
|
|
|
2399
2406
|
kind: "reconnectable",
|
|
2400
2407
|
reconnecting: false,
|
|
2401
2408
|
attempt: MAX_RECONNECT_ATTEMPTS,
|
|
2402
|
-
strategy: "fresh-grant"
|
|
2409
|
+
strategy: "fresh-grant",
|
|
2410
|
+
...recovery.reason ? { reason: recovery.reason } : {}
|
|
2403
2411
|
};
|
|
2404
2412
|
}
|
|
2405
2413
|
if (recovery.kind === "ended") {
|
|
2406
|
-
return
|
|
2414
|
+
return {
|
|
2415
|
+
kind: "ended",
|
|
2416
|
+
...recovery.reason ? { reason: recovery.reason } : {},
|
|
2417
|
+
...recovery.code ? { code: recovery.code } : {}
|
|
2418
|
+
};
|
|
2407
2419
|
}
|
|
2408
2420
|
switch (capacity.kind) {
|
|
2409
2421
|
case "idle":
|
|
@@ -2416,7 +2428,7 @@ function lifecyclePhaseFrom(args) {
|
|
|
2416
2428
|
return { kind: "ended", reason: "error" };
|
|
2417
2429
|
case "active": {
|
|
2418
2430
|
if (!connected || !agentPresent) {
|
|
2419
|
-
return { kind: "connecting", grant: capacity.grant };
|
|
2431
|
+
return { kind: "connecting", grant: capacity.grant, waitingFor: connected ? "agent" : "transport" };
|
|
2420
2432
|
}
|
|
2421
2433
|
if (idle.kind === "idle-warning") {
|
|
2422
2434
|
return { kind: "idle-warning", secondsRemaining: idle.secondsRemaining, deadlineAt: idle.deadlineAt };
|
|
@@ -2444,6 +2456,7 @@ function resolveIdleTimeoutMs(args) {
|
|
|
2444
2456
|
return DEFAULT_IDLE_SECONDS * 1e3;
|
|
2445
2457
|
}
|
|
2446
2458
|
var DEFAULT_CONNECT_WATCHDOG_SECONDS = 12;
|
|
2459
|
+
var DEFAULT_READY_TIMEOUT_SECONDS = 30;
|
|
2447
2460
|
function resolveWarnBeforeMs(idleTimeoutMs, override, idleWarnLeadSeconds) {
|
|
2448
2461
|
if (idleTimeoutMs <= 0) return 0;
|
|
2449
2462
|
const maxLeadMs = Math.max(0, idleTimeoutMs - 1e3);
|
|
@@ -2469,6 +2482,7 @@ function useSessionLifecycle(input) {
|
|
|
2469
2482
|
maxReconnectAttempts,
|
|
2470
2483
|
autoRetryBusy = true,
|
|
2471
2484
|
connectWatchdogSeconds,
|
|
2485
|
+
readyTimeoutSeconds,
|
|
2472
2486
|
requestOptions,
|
|
2473
2487
|
onBehaviorChange
|
|
2474
2488
|
} = input;
|
|
@@ -2479,17 +2493,27 @@ function useSessionLifecycle(input) {
|
|
|
2479
2493
|
const reconnectPolicyRef = useRef(reconnectPolicy);
|
|
2480
2494
|
reconnectPolicyRef.current = reconnectPolicy;
|
|
2481
2495
|
const connectWatchdogMs = typeof connectWatchdogSeconds === "number" && Number.isFinite(connectWatchdogSeconds) ? Math.max(0, Math.floor(connectWatchdogSeconds)) * 1e3 : DEFAULT_CONNECT_WATCHDOG_SECONDS * 1e3;
|
|
2496
|
+
const readyTimeoutMs = typeof readyTimeoutSeconds === "number" && Number.isFinite(readyTimeoutSeconds) && readyTimeoutSeconds > 0 ? Math.max(1, Math.floor(readyTimeoutSeconds)) * 1e3 : DEFAULT_READY_TIMEOUT_SECONDS * 1e3;
|
|
2482
2497
|
const [userEnded, setUserEnded] = useState(false);
|
|
2483
2498
|
const userEndedRef = useRef(false);
|
|
2499
|
+
const [readinessFailed, setReadinessFailed] = useState(false);
|
|
2500
|
+
const readinessFailureRef = useRef(null);
|
|
2501
|
+
const readinessRef = useRef(null);
|
|
2502
|
+
const readyGrantRef = useRef(null);
|
|
2503
|
+
const agentWaitRef = useRef(null);
|
|
2484
2504
|
const phaseRef = useRef({ kind: "idle" });
|
|
2485
2505
|
const grantState = useLiveKitAvatarGrant({
|
|
2486
2506
|
client,
|
|
2487
2507
|
session,
|
|
2488
|
-
active: active && !userEnded,
|
|
2508
|
+
active: active && !userEnded && !readinessFailed,
|
|
2489
2509
|
autoRetryBusy,
|
|
2490
2510
|
requestOptions
|
|
2491
2511
|
});
|
|
2492
2512
|
const capacity = grantState.capacity;
|
|
2513
|
+
const grantId = grantState.grant?.session_id ?? null;
|
|
2514
|
+
const grantIdRef = useRef(null);
|
|
2515
|
+
grantIdRef.current = grantId;
|
|
2516
|
+
const retiredGrantRef = useRef(null);
|
|
2493
2517
|
const [recovery, setRecovery] = useState({ kind: "connected" });
|
|
2494
2518
|
const recoveryRef = useRef(recovery);
|
|
2495
2519
|
recoveryRef.current = recovery;
|
|
@@ -2512,8 +2536,19 @@ function useSessionLifecycle(input) {
|
|
|
2512
2536
|
grantIdleSeconds: grantState.grant?.idle_timeout_seconds ?? 0
|
|
2513
2537
|
});
|
|
2514
2538
|
const warnAtMs = resolveWarnBeforeMs(idleTimeoutMs, warnBeforeMs, idleWarnLeadSeconds);
|
|
2515
|
-
const [
|
|
2516
|
-
const [
|
|
2539
|
+
const [agentObservation, setAgentObservation] = useState({ grantId: null, present: false });
|
|
2540
|
+
const [connectionObservation, setConnectionObservation] = useState({ grantId: null, connected: false });
|
|
2541
|
+
const agentPresent = agentObservation.grantId === grantId && agentObservation.present;
|
|
2542
|
+
const connected = connectionObservation.grantId === grantId && connectionObservation.connected;
|
|
2543
|
+
connectedRef.current = connected;
|
|
2544
|
+
const setAgentPresentState = useCallback((present) => {
|
|
2545
|
+
const owner = grantIdRef.current;
|
|
2546
|
+
setAgentObservation((prev) => prev.grantId === owner && prev.present === present ? prev : { grantId: owner, present });
|
|
2547
|
+
}, []);
|
|
2548
|
+
const setConnected = useCallback((value) => {
|
|
2549
|
+
const owner = grantIdRef.current;
|
|
2550
|
+
setConnectionObservation((prev) => prev.grantId === owner && prev.connected === value ? prev : { grantId: owner, connected: value });
|
|
2551
|
+
}, []);
|
|
2517
2552
|
const lastActivityRef = useRef(Date.now());
|
|
2518
2553
|
const leaveRoomRef = useRef(null);
|
|
2519
2554
|
const [, setClockTick] = useState(0);
|
|
@@ -2530,7 +2565,11 @@ function useSessionLifecycle(input) {
|
|
|
2530
2565
|
refreshBaselineCapacityRef.current = null;
|
|
2531
2566
|
attemptRef.current = 0;
|
|
2532
2567
|
setAttempt(0);
|
|
2533
|
-
|
|
2568
|
+
readinessRef.current = null;
|
|
2569
|
+
readyGrantRef.current = null;
|
|
2570
|
+
agentWaitRef.current = null;
|
|
2571
|
+
retiredGrantRef.current = null;
|
|
2572
|
+
setRecovery(userEndedRef.current ? { kind: "ended", reason: "user" } : readinessFailureRef.current ? { kind: "ended", reason: "error", code: readinessFailureRef.current } : { kind: "connected" });
|
|
2534
2573
|
setConnected(false);
|
|
2535
2574
|
setAgentPresentState(false);
|
|
2536
2575
|
lastActivityRef.current = Date.now();
|
|
@@ -2539,26 +2578,33 @@ function useSessionLifecycle(input) {
|
|
|
2539
2578
|
if (active) return;
|
|
2540
2579
|
userEndedRef.current = false;
|
|
2541
2580
|
setUserEnded(false);
|
|
2581
|
+
readinessFailureRef.current = null;
|
|
2582
|
+
setReadinessFailed(false);
|
|
2542
2583
|
reset();
|
|
2543
2584
|
}, [active, reset]);
|
|
2544
2585
|
const markActivity = useCallback(() => {
|
|
2586
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2545
2587
|
lastActivityRef.current = Date.now();
|
|
2546
2588
|
setClockTick((value) => value + 1);
|
|
2547
|
-
}, []);
|
|
2589
|
+
}, [grantId]);
|
|
2548
2590
|
const stayConnected = useCallback(() => {
|
|
2591
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2549
2592
|
if (!connectedRef.current) return;
|
|
2550
2593
|
lastActivityRef.current = Date.now();
|
|
2551
2594
|
setClockTick((value) => value + 1);
|
|
2552
|
-
}, []);
|
|
2595
|
+
}, [grantId]);
|
|
2553
2596
|
const setAgentPresent = useCallback((present) => {
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2597
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2598
|
+
if (userEndedRef.current || readinessFailureRef.current || retiredGrantRef.current !== null && retiredGrantRef.current === grantIdRef.current) return;
|
|
2599
|
+
setAgentObservation((prev) => {
|
|
2600
|
+
if (present && (prev.grantId !== grantId || !prev.present)) lastActivityRef.current = Date.now();
|
|
2601
|
+
return prev.grantId === grantId && prev.present === present ? prev : { grantId, present };
|
|
2557
2602
|
});
|
|
2558
|
-
}, []);
|
|
2603
|
+
}, [grantId]);
|
|
2559
2604
|
const registerLeaveRoom = useCallback((leave) => {
|
|
2605
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2560
2606
|
leaveRoomRef.current = leave;
|
|
2561
|
-
}, []);
|
|
2607
|
+
}, [grantId]);
|
|
2562
2608
|
const endIdle = useCallback(() => {
|
|
2563
2609
|
if (!connectedRef.current) return;
|
|
2564
2610
|
clearTimer();
|
|
@@ -2570,24 +2616,25 @@ function useSessionLifecycle(input) {
|
|
|
2570
2616
|
leaveRoomRef.current?.();
|
|
2571
2617
|
}, [clearTimer]);
|
|
2572
2618
|
const onConnected = useCallback(() => {
|
|
2573
|
-
if (
|
|
2619
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2620
|
+
if (userEndedRef.current || readinessFailureRef.current || retiredGrantRef.current !== null && retiredGrantRef.current === grantIdRef.current) return;
|
|
2574
2621
|
clearTimer();
|
|
2575
2622
|
connectedRef.current = true;
|
|
2576
2623
|
manualReconnectPendingRef.current = false;
|
|
2577
2624
|
refreshBaselineCapacityRef.current = null;
|
|
2578
2625
|
setConnected(true);
|
|
2579
|
-
|
|
2580
|
-
setAttempt(0);
|
|
2626
|
+
if (readinessRef.current) readinessRef.current.sawTransport = true;
|
|
2581
2627
|
setRecovery({ kind: "connected" });
|
|
2582
2628
|
lastActivityRef.current = Date.now();
|
|
2583
|
-
}, [clearTimer]);
|
|
2629
|
+
}, [clearTimer, grantId]);
|
|
2584
2630
|
const onDisconnected = useCallback(
|
|
2585
2631
|
(reason) => {
|
|
2586
|
-
if (
|
|
2632
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2633
|
+
if (!active || userEndedRef.current || readinessFailureRef.current) return;
|
|
2587
2634
|
const action = disconnectAction(reason, connectedRef.current);
|
|
2588
2635
|
if (action === "noop") return;
|
|
2589
2636
|
if (action === "reset") {
|
|
2590
|
-
if (recoveryRef.current.kind === "refreshing") return;
|
|
2637
|
+
if (recoveryRef.current.kind === "refreshing" || recoveryRef.current.kind === "reconnecting") return;
|
|
2591
2638
|
reset();
|
|
2592
2639
|
return;
|
|
2593
2640
|
}
|
|
@@ -2604,11 +2651,12 @@ function useSessionLifecycle(input) {
|
|
|
2604
2651
|
refreshBaselineCapacityRef.current = null;
|
|
2605
2652
|
setRecovery({ kind: "reconnecting", attempt: attemptRef.current });
|
|
2606
2653
|
},
|
|
2607
|
-
[active, reset]
|
|
2654
|
+
[active, reset, grantId]
|
|
2608
2655
|
);
|
|
2609
2656
|
const onConnectionError = useCallback(
|
|
2610
2657
|
(error) => {
|
|
2611
|
-
if (
|
|
2658
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2659
|
+
if (!active || userEndedRef.current || readinessFailureRef.current || !isRecoverableConnectionError(error)) return;
|
|
2612
2660
|
connectedRef.current = false;
|
|
2613
2661
|
setConnected(false);
|
|
2614
2662
|
setAgentPresentState(false);
|
|
@@ -2619,7 +2667,7 @@ function useSessionLifecycle(input) {
|
|
|
2619
2667
|
return { kind: "reconnecting", attempt: attemptRef.current };
|
|
2620
2668
|
});
|
|
2621
2669
|
},
|
|
2622
|
-
[active]
|
|
2670
|
+
[active, grantId]
|
|
2623
2671
|
);
|
|
2624
2672
|
useEffect(() => {
|
|
2625
2673
|
if (capacity.kind === "error" && recovery.kind === "connected") manualReconnectPendingRef.current = false;
|
|
@@ -2629,11 +2677,12 @@ function useSessionLifecycle(input) {
|
|
|
2629
2677
|
const baseline = refreshBaselineCapacityRef.current;
|
|
2630
2678
|
if (baseline?.kind === "error" && baseline.error === capacity.error) return;
|
|
2631
2679
|
refreshBaselineCapacityRef.current = null;
|
|
2632
|
-
setRecovery({ kind: "reconnecting", attempt: recovery.attempt });
|
|
2680
|
+
setRecovery({ kind: "reconnecting", attempt: recovery.attempt, ...recovery.reason ? { reason: recovery.reason } : {} });
|
|
2633
2681
|
}, [capacity, recovery]);
|
|
2634
2682
|
const onConnectionStateChange = useCallback(
|
|
2635
2683
|
(state) => {
|
|
2636
|
-
if (
|
|
2684
|
+
if (grantId === null || grantIdRef.current !== grantId) return;
|
|
2685
|
+
if (!active || userEndedRef.current || readinessFailureRef.current) return;
|
|
2637
2686
|
if (state === "connected") {
|
|
2638
2687
|
onConnected();
|
|
2639
2688
|
return;
|
|
@@ -2647,14 +2696,78 @@ function useSessionLifecycle(input) {
|
|
|
2647
2696
|
}
|
|
2648
2697
|
}
|
|
2649
2698
|
},
|
|
2650
|
-
[active, onConnected]
|
|
2699
|
+
[active, onConnected, grantId]
|
|
2651
2700
|
);
|
|
2701
|
+
useEffect(() => {
|
|
2702
|
+
if (!active || userEnded || readinessFailed || !connected || !agentPresent || !grantState.grant) return;
|
|
2703
|
+
readyGrantRef.current = grantState.grant.session_id;
|
|
2704
|
+
readinessRef.current = null;
|
|
2705
|
+
agentWaitRef.current = null;
|
|
2706
|
+
attemptRef.current = 0;
|
|
2707
|
+
setAttempt(0);
|
|
2708
|
+
}, [active, userEnded, readinessFailed, connected, agentPresent, grantState.grant]);
|
|
2709
|
+
const failReadiness = useCallback((code) => {
|
|
2710
|
+
if (userEndedRef.current || readinessFailureRef.current) return;
|
|
2711
|
+
readinessFailureRef.current = code;
|
|
2712
|
+
clearTimer();
|
|
2713
|
+
connectedRef.current = false;
|
|
2714
|
+
manualReconnectPendingRef.current = false;
|
|
2715
|
+
refreshBaselineCapacityRef.current = null;
|
|
2716
|
+
const ended = { kind: "ended", reason: "error", code };
|
|
2717
|
+
recoveryRef.current = ended;
|
|
2718
|
+
setRecovery(ended);
|
|
2719
|
+
setConnected(false);
|
|
2720
|
+
setAgentPresentState(false);
|
|
2721
|
+
releaseRef.current("disconnected");
|
|
2722
|
+
setReadinessFailed(true);
|
|
2723
|
+
leaveRoomRef.current?.();
|
|
2724
|
+
}, [clearTimer]);
|
|
2725
|
+
useEffect(() => {
|
|
2726
|
+
if (!active || userEnded || readinessFailed) return;
|
|
2727
|
+
if (recovery.kind === "ended" || recovery.kind === "failed") return;
|
|
2728
|
+
if (grantState.grant && readyGrantRef.current === grantState.grant.session_id) return;
|
|
2729
|
+
if (!readinessRef.current && grantState.grant) {
|
|
2730
|
+
readinessRef.current = { startedAt: Date.now(), sawTransport: connected };
|
|
2731
|
+
}
|
|
2732
|
+
const budget = readinessRef.current;
|
|
2733
|
+
if (!budget) return;
|
|
2734
|
+
const timer = window.setTimeout(() => {
|
|
2735
|
+
if (readinessRef.current !== budget) return;
|
|
2736
|
+
failReadiness(budget.sawTransport ? "agent_timeout" : "connection_timeout");
|
|
2737
|
+
}, Math.max(0, budget.startedAt + readyTimeoutMs - Date.now()));
|
|
2738
|
+
return () => window.clearTimeout(timer);
|
|
2739
|
+
}, [active, userEnded, readinessFailed, connected, agentPresent, grantState.grant, recovery.kind, readyTimeoutMs, failReadiness]);
|
|
2740
|
+
useEffect(() => {
|
|
2741
|
+
const sessionId = grantState.grant?.session_id;
|
|
2742
|
+
if (!active || userEnded || readinessFailed || !sessionId || readyGrantRef.current === sessionId || agentPresent) return;
|
|
2743
|
+
if (recovery.kind === "reconnecting" || recovery.kind === "failed" || recovery.kind === "ended") return;
|
|
2744
|
+
if (agentWaitRef.current?.sessionId !== sessionId) {
|
|
2745
|
+
if (!connected) return;
|
|
2746
|
+
agentWaitRef.current = { sessionId, startedAt: Date.now() };
|
|
2747
|
+
}
|
|
2748
|
+
const wait = agentWaitRef.current;
|
|
2749
|
+
if (connectWatchdogMs <= 0) return;
|
|
2750
|
+
const timer = window.setTimeout(() => {
|
|
2751
|
+
if (agentWaitRef.current !== wait || readinessFailureRef.current || userEndedRef.current) return;
|
|
2752
|
+
retiredGrantRef.current = sessionId;
|
|
2753
|
+
connectedRef.current = false;
|
|
2754
|
+
setConnected(false);
|
|
2755
|
+
setAgentPresentState(false);
|
|
2756
|
+
const next = { kind: "reconnecting", attempt: attemptRef.current, reason: "agent_timeout" };
|
|
2757
|
+
recoveryRef.current = next;
|
|
2758
|
+
setRecovery(next);
|
|
2759
|
+
releaseRef.current("disconnected");
|
|
2760
|
+
leaveRoomRef.current?.();
|
|
2761
|
+
}, Math.max(0, wait.startedAt + connectWatchdogMs - Date.now()));
|
|
2762
|
+
return () => window.clearTimeout(timer);
|
|
2763
|
+
}, [active, userEnded, readinessFailed, connected, agentPresent, grantState.grant, recovery.kind, connectWatchdogMs]);
|
|
2652
2764
|
useEffect(() => {
|
|
2653
2765
|
if (!active || connected || connectWatchdogMs <= 0) return;
|
|
2654
2766
|
if (grantState.status !== "ready" || !grantState.grant) return;
|
|
2655
2767
|
if (recovery.kind === "failed" || recovery.kind === "ended") return;
|
|
2656
2768
|
if (recovery.kind === "in-place-reconnecting") return;
|
|
2657
2769
|
const timer = window.setTimeout(() => {
|
|
2770
|
+
if (readinessFailureRef.current || userEndedRef.current) return;
|
|
2658
2771
|
releaseRef.current("disconnected");
|
|
2659
2772
|
setRecovery({ kind: "reconnecting", attempt: attemptRef.current });
|
|
2660
2773
|
}, connectWatchdogMs);
|
|
@@ -2664,6 +2777,10 @@ function useSessionLifecycle(input) {
|
|
|
2664
2777
|
if (!active || !needsFreshGrant(recovery)) return;
|
|
2665
2778
|
const step2 = retryStep(attemptRef.current, reconnectPolicyRef.current);
|
|
2666
2779
|
if (step2.kind === "give-up") {
|
|
2780
|
+
if (readinessRef.current) {
|
|
2781
|
+
failReadiness(readinessRef.current.sawTransport ? "agent_timeout" : "connection_timeout");
|
|
2782
|
+
return;
|
|
2783
|
+
}
|
|
2667
2784
|
manualReconnectPendingRef.current = false;
|
|
2668
2785
|
refreshBaselineCapacityRef.current = null;
|
|
2669
2786
|
releaseRef.current("disconnected");
|
|
@@ -2672,15 +2789,16 @@ function useSessionLifecycle(input) {
|
|
|
2672
2789
|
}
|
|
2673
2790
|
timerRef.current = window.setTimeout(() => {
|
|
2674
2791
|
timerRef.current = null;
|
|
2792
|
+
if (readinessFailureRef.current || userEndedRef.current) return;
|
|
2675
2793
|
attemptRef.current = step2.attempt;
|
|
2676
2794
|
setAttempt(step2.attempt);
|
|
2677
2795
|
refreshBaselineCapacityRef.current = capacityRef.current;
|
|
2678
2796
|
releaseRef.current("superseded");
|
|
2679
|
-
setRecovery({ kind: "refreshing", attempt: step2.attempt });
|
|
2797
|
+
setRecovery({ kind: "refreshing", attempt: step2.attempt, ...recovery.reason ? { reason: recovery.reason } : {} });
|
|
2680
2798
|
refreshRef.current();
|
|
2681
2799
|
}, step2.delayMs);
|
|
2682
2800
|
return clearTimer;
|
|
2683
|
-
}, [recovery.kind, active, attempt, clearTimer]);
|
|
2801
|
+
}, [recovery.kind, active, attempt, clearTimer, failReadiness]);
|
|
2684
2802
|
const end = useCallback(() => {
|
|
2685
2803
|
if (!active || userEndedRef.current || phaseRef.current.kind === "ended") return;
|
|
2686
2804
|
userEndedRef.current = true;
|
|
@@ -2697,6 +2815,13 @@ function useSessionLifecycle(input) {
|
|
|
2697
2815
|
}, [active, clearTimer]);
|
|
2698
2816
|
const reconnect = useCallback(() => {
|
|
2699
2817
|
if (!active) return;
|
|
2818
|
+
if (readinessFailureRef.current) {
|
|
2819
|
+
readinessFailureRef.current = null;
|
|
2820
|
+
setReadinessFailed(false);
|
|
2821
|
+
reset();
|
|
2822
|
+
manualReconnectPendingRef.current = true;
|
|
2823
|
+
return;
|
|
2824
|
+
}
|
|
2700
2825
|
if (userEndedRef.current) {
|
|
2701
2826
|
userEndedRef.current = false;
|
|
2702
2827
|
setUserEnded(false);
|
|
@@ -2707,6 +2832,12 @@ function useSessionLifecycle(input) {
|
|
|
2707
2832
|
if (manualReconnectPendingRef.current || recovery.kind === "in-place-reconnecting") return;
|
|
2708
2833
|
manualReconnectPendingRef.current = true;
|
|
2709
2834
|
clearTimer();
|
|
2835
|
+
readinessRef.current = null;
|
|
2836
|
+
agentWaitRef.current = null;
|
|
2837
|
+
readyGrantRef.current = null;
|
|
2838
|
+
connectedRef.current = false;
|
|
2839
|
+
setConnected(false);
|
|
2840
|
+
setAgentPresentState(false);
|
|
2710
2841
|
attemptRef.current = 0;
|
|
2711
2842
|
setAttempt(0);
|
|
2712
2843
|
refreshBaselineCapacityRef.current = capacityRef.current;
|
|
@@ -2826,6 +2957,7 @@ function SessionLifecycleRoomBridge({
|
|
|
2826
2957
|
const assistant = useVoiceAssistant();
|
|
2827
2958
|
const transcriptions = useTranscriptions();
|
|
2828
2959
|
const room = useRoomContext();
|
|
2960
|
+
const roomMatchesGrant = lifecycle.grant === void 0 || lifecycle.grant !== null && room.name === lifecycle.grant.room_name;
|
|
2829
2961
|
useCallMedia(room, {
|
|
2830
2962
|
setMicrophoneFacts,
|
|
2831
2963
|
setAudioPlayback,
|
|
@@ -2979,11 +3111,11 @@ function SessionLifecycleRoomBridge({
|
|
|
2979
3111
|
detailsEnabled ? video?.publication : void 0
|
|
2980
3112
|
]);
|
|
2981
3113
|
useEffect(() => {
|
|
2982
|
-
onConnectionStateChange(connectionState);
|
|
2983
|
-
}, [connectionState, onConnectionStateChange]);
|
|
3114
|
+
if (roomMatchesGrant) onConnectionStateChange(connectionState);
|
|
3115
|
+
}, [connectionState, onConnectionStateChange, roomMatchesGrant]);
|
|
2984
3116
|
useEffect(() => {
|
|
2985
|
-
setAgentPresent(agentPresent);
|
|
2986
|
-
}, [agentPresent, setAgentPresent]);
|
|
3117
|
+
if (roomMatchesGrant) setAgentPresent(agentPresent);
|
|
3118
|
+
}, [agentPresent, setAgentPresent, roomMatchesGrant]);
|
|
2987
3119
|
useEffect(() => {
|
|
2988
3120
|
const active = isCallActivity({
|
|
2989
3121
|
assistantState,
|
|
@@ -3691,4 +3823,4 @@ function createProxyClient(options) {
|
|
|
3691
3823
|
};
|
|
3692
3824
|
}
|
|
3693
3825
|
|
|
3694
|
-
export { AdaptivePlayoutController, AvatarVideoSurface, DEFAULT_APPROACHING_END_LEAD_SECONDS, DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS, DEFAULT_CREDITS_LOW_LEAD_SECONDS, DEFAULT_GOVERNOR_CONFIG, DEFAULT_GRACE_CEILING_SECONDS, DEFAULT_GRACE_WINDOW_LEAD_SECONDS, DEFAULT_IDLE_SECONDS, DEFAULT_IDLE_WARN_LEAD_SECONDS, DEFAULT_TURN_TIMEOUT_SECONDS, MAX_RECONNECT_ATTEMPTS, MAX_SESSION_INSTRUCTIONS_CHARS, RECONNECT_BACKOFF_MS, RealtimeAvatarLiveKitRoom, SessionLifecycleRoomBridge, capacityErrorFromBusy, capacityStateFromGrant, createProxyClient, isNativeLiveTrackSubscribed, knownBehaviorStates, mapTurnState, readInboundRtp, sessionBehaviorSchema, sessionClipSchema, splitCallTranscript, useAvatarAdaptivePlayoutDelay, useAvatarCamera, useAvatarPlayoutDelay, useAvatarQualityGovernor, useCallTranscript, useLiveKitAvatarGrant, useLiveTrackProducing, useMicLease, useRealtimeAvatarAudioSession, useRealtimeSession, useReleaseMicLeaseOnTrackEnded, useSessionLifecycle };
|
|
3826
|
+
export { AdaptivePlayoutController, AvatarVideoSurface, DEFAULT_APPROACHING_END_LEAD_SECONDS, DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS, DEFAULT_CREDITS_LOW_LEAD_SECONDS, DEFAULT_GOVERNOR_CONFIG, DEFAULT_GRACE_CEILING_SECONDS, DEFAULT_GRACE_WINDOW_LEAD_SECONDS, DEFAULT_IDLE_SECONDS, DEFAULT_IDLE_WARN_LEAD_SECONDS, DEFAULT_READY_TIMEOUT_SECONDS, DEFAULT_TURN_TIMEOUT_SECONDS, MAX_RECONNECT_ATTEMPTS, MAX_SESSION_INSTRUCTIONS_CHARS, RECONNECT_BACKOFF_MS, RealtimeAvatarLiveKitRoom, SessionLifecycleRoomBridge, capacityErrorFromBusy, capacityStateFromGrant, createProxyClient, isNativeLiveTrackSubscribed, knownBehaviorStates, mapTurnState, readInboundRtp, sessionBehaviorSchema, sessionClipSchema, splitCallTranscript, useAvatarAdaptivePlayoutDelay, useAvatarCamera, useAvatarPlayoutDelay, useAvatarQualityGovernor, useCallTranscript, useLiveKitAvatarGrant, useLiveTrackProducing, useMicLease, useRealtimeAvatarAudioSession, useRealtimeSession, useReleaseMicLeaseOnTrackEnded, useSessionLifecycle };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ToolRegistration, RegisteredTool } from './tools.js';
|
|
2
|
-
import {
|
|
3
|
-
export { a as AdaptivePlayoutController, b as AdaptivePlayoutDecision, c as AdaptivePlayoutOptions, d as AdaptivePlayoutSample, e as ApproachingEndEvent, f as ApproachingEndReason, g as AvatarConnectionDetails,
|
|
2
|
+
import { ak as SessionLifecycleRoomBridgeProps, h as AvatarSessionClient, A as AvatarVideoFit, aS as CallMicrophone, aT as CallAudioPlayback, aU as CallMicrophoneProblem } from './proxy-client-Cs2azqD1.js';
|
|
3
|
+
export { a as AdaptivePlayoutController, b as AdaptivePlayoutDecision, c as AdaptivePlayoutOptions, d as AdaptivePlayoutSample, e as ApproachingEndEvent, f as ApproachingEndReason, g as AvatarConnectionDetails, aV as AvatarVideoSurface, aW as AvatarVideoSurfaceProps, B as BehaviorSnapshot, C as CallTranscript, i as CallTranscriptSegment, j as CartesiaTtsModel, k as ClipResult, l as ClosingTurnResult, m as CreditsLowEvent, D as DEFAULT_APPROACHING_END_LEAD_SECONDS, n as DEFAULT_CREDITS_LOW_LEAD_SECONDS, o as DEFAULT_GOVERNOR_CONFIG, p as DEFAULT_GRACE_CEILING_SECONDS, q as DEFAULT_GRACE_WINDOW_LEAD_SECONDS, r as DEFAULT_IDLE_SECONDS, s as DEFAULT_IDLE_WARN_LEAD_SECONDS, t as DEFAULT_READY_TIMEOUT_SECONDS, u as DEFAULT_TURN_TIMEOUT_SECONDS, v as DeclaredInputSource, E as EndReason, w as EndedEvent, x as ExtendResult, F as FishTtsModel, y as FreezeReadingFn, G as Governor, z as GovernorAction, H as GovernorConfig, I as GovernorSignal, J as GovernorState, K as GraceWindowClosedEvent, M as GraceWindowOpenEvent, N as GraceWindowState, O as IdleWarningEvent, P as InboundRtpCursor, Q as InboundRtpReading, R as KnownBehaviorState, S as LLMProvider, T as LLMSelection, U as LiveKitAvatarGrantState, V as LiveKitAvatarGrantStatus, W as LiveKitCapacityState, X as LiveKitConnectionStatus, Y as LiveKitSessionRequest, Z as LiveKitSessionStartResult, aX as LivePlaybackKeeper, _ as MAX_RECONNECT_ATTEMPTS, $ as MAX_SESSION_INSTRUCTIONS_CHARS, aY as MIC_LEASE_ENDED_TIMEOUT_MS, aZ as MicLease, a_ as NETWORK_QUALITY_POLICY, a$ as NetworkQualityStatus, b0 as PlayableVideoElement, a0 as ProxyClientOptions, a1 as QualityCap, a2 as RECONNECT_BACKOFF_MS, b1 as RealtimeAvatarCapacityError, b2 as RealtimeAvatarLiveKitRoom, b3 as RealtimeAvatarLiveKitRoomProps, a3 as RealtimeAvatarRequestOptions, a4 as RealtimeSessionApi, a5 as RealtimeSessionMedia, a6 as RealtimeSessionRoomSinks, a7 as ReconnectPolicy, a8 as ReconnectingEvent, a9 as RecoveryState, aa as RetryStep, ab as SendTurnOptions, ac as SessionBehavior, ad as SessionClip, ae as SessionClocks, af as SessionEndReason, ag as SessionLifecycleApi, ah as SessionLifecyclePhase, ai as SessionLifecyclePhaseKind, aj as SessionLifecycleRoomBridge, al as SessionReadinessFailure, am as SurfaceLayers, an as TranscriptSender, ao as TranscriptSenderOptions, ap as TurnState, aq as TurnTimeoutEvent, ar as UseAvatarQualityGovernorInput, as as UseLiveKitAvatarGrantInput, at as UseRealtimeSessionInput, au as UseSessionLifecycleInput, av as VoiceSpec, aw as VoiceSpecInput, ax as capacityErrorFromBusy, ay as capacityStateFromGrant, az as createProxyClient, aB as knownBehaviorStates, aC as mapTurnState, aD as readInboundRtp, aE as sessionBehaviorSchema, aF as sessionClipSchema, b4 as shouldReplayPendingTurn, aG as splitCallTranscript, aH as useAvatarAdaptivePlayoutDelay, aI as useAvatarCamera, aJ as useAvatarPlayoutDelay, aK as useAvatarQualityGovernor, aL as useCallTranscript, aM as useLiveKitAvatarGrant, aO as useMicLease, aP as useRealtimeSession, aQ as useReleaseMicLeaseOnTrackEnded, aR as useSessionLifecycle } from './proxy-client-Cs2azqD1.js';
|
|
4
4
|
import { CSSProperties, ReactNode } from 'react';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
import { R as RecordingArtifact } from './recording-DjswTx5B.js';
|
|
@@ -138,6 +138,11 @@ type AvatarCallProps = Pick<SessionLifecycleRoomBridgeProps, "onConnectionDetail
|
|
|
138
138
|
/** A still shown before the idle clip is playable. */
|
|
139
139
|
poster?: string | null;
|
|
140
140
|
fit?: AvatarVideoFit;
|
|
141
|
+
/**
|
|
142
|
+
* The small "live" badge over the video while she is live. Default true. Set false when your
|
|
143
|
+
* own UI already shows the call's status.
|
|
144
|
+
*/
|
|
145
|
+
showLiveBadge?: boolean;
|
|
141
146
|
/** Adds your classes to the call's box. The box sizes itself inline; to resize it, use `style`. */
|
|
142
147
|
className?: string;
|
|
143
148
|
/** Inline style for the call's box, spread over its own (`height`, `aspectRatio`, …). */
|