From 994d2d97eb473d14f06de37b4f9fb2e9f0356381 Mon Sep 17 00:00:00 2001 From: duyalei <269870927@qq.com> Date: Mon, 23 Jun 2025 11:21:56 +0800 Subject: [PATCH 1/3] feat: add keyboard to mock a phone call --- src/components/config/Keyboard.tsx | 79 ++++++++++++++++++++++++ src/components/playground/Playground.tsx | 10 +++ 2 files changed, 89 insertions(+) create mode 100644 src/components/config/Keyboard.tsx diff --git a/src/components/config/Keyboard.tsx b/src/components/config/Keyboard.tsx new file mode 100644 index 00000000..3c627001 --- /dev/null +++ b/src/components/config/Keyboard.tsx @@ -0,0 +1,79 @@ +import React, { useState } from "react"; +import { LocalParticipant } from "livekit-client"; + +interface KeyboardProps { + localParticipant: LocalParticipant; + className?: string; +} + +interface KeyConfig { + label: string; + intKey: number; + strKey: string; +} + +const keyConfigs: KeyConfig[] = [ + { label: "1", intKey: 1, strKey: "1" }, + { label: "2", intKey: 2, strKey: "2" }, + { label: "3", intKey: 3, strKey: "3" }, + { label: "4", intKey: 4, strKey: "4" }, + { label: "5", intKey: 5, strKey: "5" }, + { label: "6", intKey: 6, strKey: "6" }, + { label: "7", intKey: 7, strKey: "7" }, + { label: "8", intKey: 8, strKey: "8" }, + { label: "9", intKey: 9, strKey: "9" }, + { label: "*", intKey: 10, strKey: "*" }, + { label: "0", intKey: 0, strKey: "0" }, + { label: "#", intKey: 11, strKey: "#" }, +]; + +export const Keyboard: React.FC = ({ + localParticipant, + className = "", +}) => { + const [pressedKey, setPressedKey] = useState(null); + + const handleKeyPress = async (keyConfig: KeyConfig) => { + setPressedKey(keyConfig.label); + console.log("Publishing DTMF:", keyConfig.label); + + try { + await localParticipant.publishDtmf(keyConfig.intKey, keyConfig.strKey); + } catch (error) { + console.error("Failed to publish DTMF:", error); + } finally { + setTimeout(() => { + setPressedKey(null); + }, 150); + } + }; + + return ( +
+
+
+ {keyConfigs.map((keyConfig) => ( + + ))} +
+
+
+ ); +}; diff --git a/src/components/playground/Playground.tsx b/src/components/playground/Playground.tsx index 77d3cc2f..3e44e5f4 100644 --- a/src/components/playground/Playground.tsx +++ b/src/components/playground/Playground.tsx @@ -5,6 +5,7 @@ import { ChatMessageType } from "@/components/chat/ChatTile"; import { ColorPicker } from "@/components/colorPicker/ColorPicker"; import { AudioInputTile } from "@/components/config/AudioInputTile"; import { ConfigurationPanelItem } from "@/components/config/ConfigurationPanelItem"; +import { Keyboard } from "@/components/config/Keyboard"; import { NameValueRow } from "@/components/config/NameValueRow"; import { PlaygroundHeader } from "@/components/playground/PlaygroundHeader"; import { @@ -255,6 +256,15 @@ export default function Playground({ )} + {localParticipant && ( + + + + )} +
Date: Mon, 23 Jun 2025 14:54:24 +0800 Subject: [PATCH 2/3] show pressed seq --- src/components/config/Keyboard.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/config/Keyboard.tsx b/src/components/config/Keyboard.tsx index 3c627001..86b2f14d 100644 --- a/src/components/config/Keyboard.tsx +++ b/src/components/config/Keyboard.tsx @@ -32,9 +32,11 @@ export const Keyboard: React.FC = ({ className = "", }) => { const [pressedKey, setPressedKey] = useState(null); + const [pressedSequence, setPressedSequence] = useState([]); const handleKeyPress = async (keyConfig: KeyConfig) => { setPressedKey(keyConfig.label); + setPressedSequence((seq) => [...seq, keyConfig.label]); console.log("Publishing DTMF:", keyConfig.label); try { @@ -51,6 +53,9 @@ export const Keyboard: React.FC = ({ return (
+
+ {pressedSequence.length > 0 ? pressedSequence.join(' ') : ''} +
{keyConfigs.map((keyConfig) => ( - ))} + disabled={pressedKey !== null} + > + {keyConfig.label} + + ))} +
-
- ); -}; + ); + } +); + +Keyboard.displayName = "Keyboard"; diff --git a/src/components/playground/Playground.tsx b/src/components/playground/Playground.tsx index 3e44e5f4..97553f92 100644 --- a/src/components/playground/Playground.tsx +++ b/src/components/playground/Playground.tsx @@ -5,7 +5,7 @@ import { ChatMessageType } from "@/components/chat/ChatTile"; import { ColorPicker } from "@/components/colorPicker/ColorPicker"; import { AudioInputTile } from "@/components/config/AudioInputTile"; import { ConfigurationPanelItem } from "@/components/config/ConfigurationPanelItem"; -import { Keyboard } from "@/components/config/Keyboard"; +import { Keyboard, KeyboardRef } from "@/components/config/Keyboard"; import { NameValueRow } from "@/components/config/NameValueRow"; import { PlaygroundHeader } from "@/components/playground/PlaygroundHeader"; import { @@ -29,7 +29,7 @@ import { } from "@livekit/components-react"; import { ConnectionState, LocalParticipant, Track } from "livekit-client"; import { QRCodeSVG } from "qrcode.react"; -import { ReactNode, useCallback, useEffect, useMemo, useState } from "react"; +import React, { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react"; import tailwindTheme from "../../lib/tailwindTheme.preval"; import { EditableNameValueRow } from "@/components/config/NameValueRow"; import { AttributesInspector } from "@/components/config/AttributesInspector"; @@ -68,6 +68,8 @@ export default function Playground({ const [rpcPayload, setRpcPayload] = useState(""); const [showRpc, setShowRpc] = useState(false); + const keyboardRef = useRef(null); + useEffect(() => { if (roomState === ConnectionState.Connected) { localParticipant.setCameraEnabled(config.settings.inputs.camera); @@ -259,6 +261,7 @@ export default function Playground({ {localParticipant && ( @@ -560,6 +563,13 @@ export default function Playground({ ), }); + const handleConnectClick = () => { + if (roomState !== ConnectionState.Disconnected) { + keyboardRef.current?.setPressedSequence([]); + } + onConnect(roomState === ConnectionState.Disconnected); + }; + return ( <> - onConnect(roomState === ConnectionState.Disconnected) - } + onConnectClicked={handleConnectClick} />