nanobot-voice-interface/frontend/src/hooks/usePushToTalk.ts
2026-03-06 22:51:19 -05:00

54 lines
1.5 KiB
TypeScript

import { useCallback, useRef, useState } from "preact/hooks";
import type { AgentState } from "../types";
export interface PushToTalkState {
pttPressed: boolean;
micStream: MediaStream | null;
beginPTT(): void;
endPTT(): void;
}
interface UsePushToTalkOptions {
connected: boolean;
agentState: AgentState;
onPttChange(pressed: boolean): void;
onSetAgentState(state: AgentState): void;
onShowStatus(text: string, persistMs?: number): void;
}
export function usePushToTalk({
connected,
onPttChange,
onSetAgentState,
onShowStatus,
}: UsePushToTalkOptions): PushToTalkState {
const [pttPressed, setPttPressed] = useState(false);
const micStreamRef = useRef<MediaStream | null>(null);
// Attach mic stream from RTCPeerConnection tracks — caller passes it via micStream prop
// Here we track from the parent. Mic enable/disable is done by the parent hook.
const beginPTT = useCallback(() => {
if (!connected) return;
if (pttPressed) return;
setPttPressed(true);
onPttChange(true);
onSetAgentState("listening");
onShowStatus("Listening...");
}, [connected, pttPressed, onPttChange, onSetAgentState, onShowStatus]);
const endPTT = useCallback(() => {
if (!pttPressed) return;
setPttPressed(false);
onPttChange(false);
onSetAgentState("idle");
if (connected) onShowStatus("Hold anywhere to talk", 1800);
}, [pttPressed, onPttChange, onSetAgentState, onShowStatus, connected]);
return {
pttPressed,
micStream: micStreamRef.current,
beginPTT,
endPTT,
};
}