بوت صوتي
يحصل /join على تذكرة صوت، ويتصل بالقناة الصوتية إذا ثُبّت @livekit/rtc-node.
قبل أن تبدأ
أنشئ تطبيقًا وثبّته في سيرفر اختبار واضبط ثلاثة متغيرات بيئة (انظر شغّل بوتك):
export ZRZUR_BOT_TOKEN=YOUR_BOT_TOKEN
export ZRZUR_API_URL=https://api.zrzur.com
export ZRZUR_WS_URL=wss://events.zrzur.comالكود
// Voice: `/join` gets a ticket for the caller's voice channel. Audio goes
// through LiveKit; with `@livekit/rtc-node` installed the bot connects and
// can publish an audio track. Without it, the bot only shows the ticket step.
import { Client } from "@zrzur/sdk/bot";
const bot = new Client({
token: process.env.ZRZUR_BOT_TOKEN,
apiUrl: process.env.ZRZUR_API_URL,
wsUrl: process.env.ZRZUR_WS_URL,
});
bot.command("join", async (i) => {
const channel = i.option("channel");
await i.defer({ ephemeral: true });
// POST /channels/{id}/join_call → { url, token } (needs Connect)
const ticket = await bot.voice.join(channel);
let livekit;
try {
livekit = await import("@livekit/rtc-node");
} catch {
return i.editReply(
`Got a voice ticket for node ${ticket.node}. Install @livekit/rtc-node to connect.`,
);
}
const room = new livekit.Room();
await room.connect(ticket.url, ticket.token, { autoSubscribe: false });
// publish audio: create an AudioSource, a LocalAudioTrack from it, then
// room.localParticipant.publishTrack(track, options) and feed 48 kHz frames
await i.editReply("Joined the voice channel.");
});
await bot.login();
await bot.syncCommands([
{
name: "join",
description: "Join a voice channel",
options: [
{
type: "Channel",
name: "channel",
description: "Voice channel",
required: true,
channel_types: ["Voice"],
},
],
},
]);
console.log("ready");
شغّله بالأمر node voice.mjs.
جرّبه
شغّل /join channel:#voice. يحتاج البوت إلى Connect (وإلى Speak ليُسمع).
ما يوضحه
- يعيد
POST /channels/{target}/join_callعنوان LiveKit ورمزًا. - يمر الصوت نفسه عبر LiveKit، وانظر الصوت لنشر الصوت.
- يغطي اختبارنا الحي خطوة التذكرة من هذا الملف، وفُحص نشر الصوت منفصلًا على سيرفر LiveKit حقيقي.