如何在 Node JS 中为 Discord 机器人将原始 PCM 流转换为 opus 或 wav 流?

问题描述 投票:0回答:1

背景:

我正在为 Discord 创建个人音乐机器人,主要使用 discord.js,我想添加的功能之一是让机器人直接从 Voicemeeter 播放音频。这个解决方案是最佳的,因为机器人能够以比 Discord 用户更好的质量进行流式传输,并且它们能够播放立体声而不是单声道,而且我可以选择使用 Voicemeeter 流式传输的源。

Voicemeeter 带有一个称为 VBAN 的功能,它允许您使用 VBAN 协议 通过网络将音频数据发送到另一台运行 VBAN 接收器的计算机。

Jacob Bower 在 Node JS 中制作了一个 VBAN 接收器脚本,它获取原始 PCM 音频数据并使用节点扬声器通过扬声器播放它。

问题:

使用 Jacob 的脚本,如果您尝试将 PCM 音频直接通过管道传输到 Discord 机器人中,它会给出错误“错误 [VOICE_PLAY_INTERFACE_BAD_TYPE]:未知流类型。”我相信这是因为从脚本接收到的 PCM 音频包含在一个 Buffer 中,discord 机器人无法在本地播放它。我需要找到一种方法以可读格式获取 PCM 音频,以便 discord 机器人播放。 (我认为可读格式包括 opus 和 wav,(可能还有其他非 PCM 的流媒体格式))

我尝试过的:

  • 如上所述,我直接将 PCM 音频缓冲区通过管道传输到机器人中,它给出了那个错误。
  • 我尝试将缓冲区放入 PassThrough Stream,并将该流通过管道传输到机器人中。 这在控制台中没有出现任何错误,机器人按应有的方式加入了语音通道,并且没有发出任何声音。我认为这是因为 discord.js 不支持播放我后来了解到的原始 PCM 音频。
  • Discord.js 指南 提到 PCM 需要用 opus 编码才能播放 discord。 所以我尝试使用 discord.js 内置的 opus 编码器。首先,我尝试对每个 PCM 缓冲区进行编码并将其写入 PassThrough 流。
const { OpusEncoder } = require('@discordjs/opus');
const { PassThrough } = require('stream');
const EncodedStream = new PassThrough();
const encoder = new OpusEncoder(48000, 2); //48000 hz, 2 channels

. . .

if (data.header.sp == 0) { //This code executes each time there is a new frame sent from VBAN
     EncodedStream.write(encoder.encode(data.audio));
}

. . .

connection.play(EncodedStream); //Connection is just the Bot being inside a voice channel.

遇到错误

"Cannot create a Buffer larger than 0xffffffff bytes."
我不确定为什么会出现该错误,因为在每个缓冲区上运行 Buffer.byteLength 都会产生 1024.

  • 然后我继续尝试使用 prism-media 对流进行编码,发现更多错误和更多机器人保持沉默。
  • 我安装了一些声称可以将流转换为 AudioBuffers 的 npm 模块,以及另一个可以将 PCM AudioBuffer 转换为可用的 wav 格式的模块,但我在那里也发现了更多错误。

我现在无能为力,试图解决这个问题,任何帮助我指出正确方向的人都将不胜感激。

node.js audio discord.js pcm opus
1个回答
-1
投票

向上,我有同样的问题,我无法播放 mu-law 8kz 来与 api v13 不一致。我曾尝试使用 wavefile 将其转换为 pcm,然后使用 opus 对其进行编码,但我遇到了与“无法创建大于 0xffffffff 字节的缓冲区”相同的错误。我已在 @discord/voice 问题上阅读了它opus 编码功能需要有 2.5ms 缓冲区的倍数才能工作。

如果有人可以帮助我们,我将不胜感激!

   const payload = Buffer.from(msg.media.payload, "base64");

            console.log('playload', payload);

            // // Pad the input buffer with zeros if needed
            // const paddingBytes = Math.ceil(pcmBuffer.length / 160) * 160 - pcmBuffer.length;

            // if (paddingBytes > 0) {
            //     const paddingBuffer = Buffer.alloc(paddingBytes);
            //     pcmBuffer = Buffer.concat([pcmBuffer, paddingBuffer]);
            // }

            // // Create the encoder.
            // // Specify 16kHz sampling rate and 2 channel size.
            // const encoder = new OpusEncoder(8000, 1);

            // // // Encode and decode.
            // const encoded = encoder.encode(pcmBuffer);

            const resource = createAudioResource(createReadStream(pcmBuffer), { 
                inputType: StreamType.Raw
            });

            player.play(resource);

            connection.subscribe(player);
© www.soinside.com 2019 - 2024. All rights reserved.