feat: implement Opus demuxing for browser streams, cache headers for playback, and enable microphone input in recorder
This commit is contained in:
@@ -1,8 +0,0 @@
|
|||||||
# Discord Bot Token (dari Discord Developer Portal)
|
|
||||||
DISCORD_TOKEN=""
|
|
||||||
|
|
||||||
# ID Channel Voice yang ingin di-join bot saat startup
|
|
||||||
VOICE_CHANNEL_ID=
|
|
||||||
GUILD_ID=
|
|
||||||
# Folder penyimpanan rekaman (opsional, default: ./recordings)
|
|
||||||
RECORDINGS_DIR=./recordings
|
|
||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
} from "@discordjs/voice";
|
} from "@discordjs/voice";
|
||||||
import { Readable } from "stream";
|
import { Readable } from "stream";
|
||||||
|
|
||||||
|
import prism from "prism-media";
|
||||||
|
|
||||||
export class DiscordPlayer {
|
export class DiscordPlayer {
|
||||||
private player: AudioPlayer;
|
private player: AudioPlayer;
|
||||||
private connection: VoiceConnection | null = null;
|
private connection: VoiceConnection | null = null;
|
||||||
@@ -30,12 +32,13 @@ export class DiscordPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public playStream(stream: Readable) {
|
public playStream(stream: Readable) {
|
||||||
// We assume the stream is Opus or PCM.
|
// Use WebmDemuxer to extract Opus packets from browser stream
|
||||||
// For MediaRecorder (webm/opus), we might need to parse it.
|
const demuxer = new prism.opus.WebmDemuxer();
|
||||||
// But let's start with a simple resource.
|
|
||||||
const resource = createAudioResource(stream, {
|
const resource = createAudioResource(stream.pipe(demuxer), {
|
||||||
inputType: StreamType.WebmOpus,
|
inputType: StreamType.Opus,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.player.play(resource);
|
this.player.play(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export async function startRecording(client: Client, channel: VoiceChannel): Pro
|
|||||||
guildId: channel.guild.id,
|
guildId: channel.guild.id,
|
||||||
adapterCreator: channel.guild.voiceAdapterCreator as any,
|
adapterCreator: channel.guild.voiceAdapterCreator as any,
|
||||||
selfDeaf: false,
|
selfDeaf: false,
|
||||||
selfMute: true,
|
selfMute: false,
|
||||||
debug: true,
|
debug: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,17 @@ export function startWebserver(port: number = 3000) {
|
|||||||
const wss = new WebSocketServer({ server });
|
const wss = new WebSocketServer({ server });
|
||||||
|
|
||||||
const listeners = new Set<express.Response>();
|
const listeners = new Set<express.Response>();
|
||||||
|
let headerChunks: Buffer[] = [];
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, "../public")));
|
app.use(express.static(path.join(__dirname, "../public")));
|
||||||
|
|
||||||
// Endpoint for receiving (listening) audio from Discord
|
// Endpoint for receiving (listening) audio from Discord
|
||||||
app.get("/listen", (req, res) => {
|
app.get("/listen", (req, res) => {
|
||||||
res.setHeader("Content-Type", "audio/ogg");
|
res.setHeader("Content-Type", "audio/ogg");
|
||||||
|
|
||||||
|
// Send cached headers so the browser can decode the stream
|
||||||
|
headerChunks.forEach(chunk => res.write(chunk));
|
||||||
|
|
||||||
listeners.add(res);
|
listeners.add(res);
|
||||||
console.log(`[webserver] New listener connected. Total: ${listeners.size}`);
|
console.log(`[webserver] New listener connected. Total: ${listeners.size}`);
|
||||||
|
|
||||||
@@ -28,6 +33,10 @@ export function startWebserver(port: number = 3000) {
|
|||||||
|
|
||||||
// Function to broadcast audio chunks to all listeners
|
// Function to broadcast audio chunks to all listeners
|
||||||
(global as any).broadcastToWeb = (chunk: Buffer) => {
|
(global as any).broadcastToWeb = (chunk: Buffer) => {
|
||||||
|
// Store the first two chunks as headers (OpusHead and OpusTags)
|
||||||
|
if (headerChunks.length < 2) {
|
||||||
|
headerChunks.push(chunk);
|
||||||
|
}
|
||||||
listeners.forEach(res => res.write(chunk));
|
listeners.forEach(res => res.write(chunk));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user