Improving the structure
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ScrollArea } from "../ui/scroll-area";
|
import { ScrollArea } from "../ui/scroll-area";
|
||||||
import { Server, Channel } from "@/types/types";
|
import { Channel } from "@/types/types";
|
||||||
import { Card } from "../ui/card";
|
import { Card } from "../ui/card";
|
||||||
import { HashIcon, PhoneOff, Volume2Icon } from "lucide-react";
|
import { HashIcon, Volume2Icon } from "lucide-react";
|
||||||
import App from "@/types/app";
|
import App from "@/types/app";
|
||||||
import { Button } from "../ui/button";
|
|
||||||
|
|
||||||
export function ChannelIcon({ kind }: { kind: "text" | "voice" }) {
|
export function ChannelIcon({ kind }: { kind: "text" | "voice" }) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
@@ -50,15 +49,6 @@ export default function SidebarChannels({ app }: { app: App }) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
|
||||||
<footer className="mt-auto mx-3 mb-2 h-10">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
className="text-destructive hover:bg-destructive/20 hover:text-destructive"
|
|
||||||
>
|
|
||||||
<PhoneOff />
|
|
||||||
</Button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default function ChannelView({
|
|||||||
}}
|
}}
|
||||||
sendVoice={(data) => {
|
sendVoice={(data) => {
|
||||||
while (!serverRef.current || serverRef.current?.CONNECTING) {}
|
while (!serverRef.current || serverRef.current?.CONNECTING) {}
|
||||||
sendVoice(serverRef.current, 0, data);
|
sendVoice(serverRef.current, data);
|
||||||
}}
|
}}
|
||||||
indicators={indicators.filter(
|
indicators={indicators.filter(
|
||||||
(indicator) =>
|
(indicator) =>
|
||||||
|
|||||||
@@ -5,27 +5,72 @@ import { ClientMessage, IndicatorContext } from "@/types/protocol";
|
|||||||
import { Message } from "@/types/types";
|
import { Message } from "@/types/types";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { startMic } from "@/lib/audio";
|
import { startMic } from "@/lib/audio";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import {
|
||||||
|
ChevronLeftIcon,
|
||||||
|
PhoneCall,
|
||||||
|
PhoneOff,
|
||||||
|
Volume2Icon,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
export default function VoiceBox({
|
export default function VoiceBox({
|
||||||
sendVoice,
|
sendVoice,
|
||||||
|
app,
|
||||||
|
channelName,
|
||||||
}: {
|
}: {
|
||||||
app: App;
|
app: App;
|
||||||
sendRequest: (req: ClientMessage) => void;
|
sendRequest: (req: ClientMessage) => void;
|
||||||
channelName?: string;
|
channelName?: string;
|
||||||
channelIcon?: string;
|
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
indicators: IndicatorContext[];
|
indicators: IndicatorContext[];
|
||||||
sendVoice: (data: Int16Array) => void;
|
sendVoice: (data: Int16Array) => void;
|
||||||
}) {
|
}) {
|
||||||
|
const [voiceConn, setVoiceConn] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!voiceConn) return;
|
||||||
|
|
||||||
const stop = startMic(sendVoice);
|
const stop = startMic(sendVoice);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
stop.then((s) => s());
|
stop.then((s) => s());
|
||||||
};
|
};
|
||||||
}, []);
|
}, [voiceConn]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-svh w-full max-h-svh flex flex-col pb-5 pl-5 gap-5" />
|
<div className="h-svh w-full max-h-svh flex flex-col pb-5 pl-5 pr-5 gap-5">
|
||||||
|
{channelName && (
|
||||||
|
<header className="h-12 py-4 flex items-center border-b text-sm font-semibold w-full">
|
||||||
|
<span
|
||||||
|
onClick={() => app.setSidebarOpen(true)}
|
||||||
|
className="cursor-pointer flex gap-2"
|
||||||
|
>
|
||||||
|
<ChevronLeftIcon className="w-5 h-5 my-auto md:hidden" />
|
||||||
|
<Volume2Icon className="w-4 h-4 my-auto" />
|
||||||
|
{channelName}
|
||||||
|
</span>
|
||||||
|
</header>
|
||||||
|
)}
|
||||||
|
{voiceConn ? (
|
||||||
|
<div className="h-full w-full">
|
||||||
|
<footer className="mt-auto h-max">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="text-destructive hover:bg-destructive/20 hover:text-destructive"
|
||||||
|
onClick={() => setVoiceConn(false)}
|
||||||
|
>
|
||||||
|
<PhoneOff />
|
||||||
|
</Button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
className="w-max mx-auto my-auto h-max bg-transparent text-chart-2 border border-chart-2 hover:bg-chart-2/20"
|
||||||
|
onClick={() => setVoiceConn(true)}
|
||||||
|
>
|
||||||
|
Join <PhoneCall />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -62,14 +62,8 @@ function float32ToPCM16(float32: Float32Array): Int16Array {
|
|||||||
return pcm16;
|
return pcm16;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendVoice(ws: WebSocket, voiceId: number, pcm: Int16Array) {
|
export function sendVoice(ws: WebSocket, pcm: Int16Array) {
|
||||||
const buffer = new ArrayBuffer(2 + pcm.byteLength);
|
ws.send(new Uint8Array(pcm.buffer, pcm.byteOffset, pcm.byteLength));
|
||||||
const view = new DataView(buffer);
|
|
||||||
|
|
||||||
view.setUint16(0, voiceId, true); // little endian
|
|
||||||
new Uint8Array(buffer, 2).set(new Uint8Array(pcm.buffer));
|
|
||||||
|
|
||||||
ws.send(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx: AudioContext | null = null;
|
let ctx: AudioContext | null = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user