node.js - 如何在 Node JS 中将原始 PCM 流转换为 Discord 机器人的 opus 或 wav 流?
问题描述
背景:
我正在为Discord创建一个个人音乐机器人,主要使用discord.js,我想添加的功能之一是让机器人直接从Voicemeeter播放音频。这个解决方案是最佳的,因为机器人能够以比 Discord 用户更好的质量进行流式传输,并且它们能够播放立体声而不是单声道,而且我可以选择使用 Voicemeeter 流式传输的源。
Voicemeeter 带有一个称为 VBAN 的功能,它允许您使用VBAN 协议通过网络将音频数据发送到另一台运行 VBAN 接收器的计算机。
Jacob Bower 在 Node JS 中制作了一个VBAN 接收器脚本,该脚本获取原始 PCM 音频数据并使用 node-speaker 通过扬声器播放。
问题:
使用 Jacob 的脚本,如果您尝试将 PCM 音频直接通过管道传输到 Discord 机器人,则会出现错误“错误 [VOICE_PLAY_INTERFACE_BAD_TYPE]:未知流类型。” 我相信这是因为从脚本接收到的 PCM 音频包含在缓冲区中,discord bot 无法在本地播放。我需要找到一种方法以可读格式获取该 PCM 音频,以便不和谐机器人播放。(我认为可读格式包括 opus 和 wav,(可能还有其他不是 PCM 的流媒体格式))
我试过的:
- 如上所述,我直接将 PCM 音频缓冲区通过管道传输到机器人中,它给出了该错误。
- 我尝试将缓冲区放入 PassThrough Stream,并将该流通过管道传输到机器人中。这在控制台中没有遇到任何错误,机器人按照应有的方式加入语音通道,并且不发出任何声音。我认为这是因为 discord.js 不支持播放我事后学到的原始 PCM 音频。
- Discord.js 指南提到 PCM 需要使用 opus 进行编码才能在不和谐上播放。所以我尝试使用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 格式的模块,但我也发现了更多错误。
我现在正在努力解决这个问题,任何帮助我指向正确方向的帮助将不胜感激。
解决方案
推荐阅读
- python - 在 Python 中使用 OGR 几何十六进制数据
- python - 将循环中创建的每个序列与前一个序列进行比较
- spring-security - 使用redis作为会话存储的keycloak backchannel logout spring session
- r - Cstack 大小限制问题 - r
- karate - 如何在不更改项目结构的情况下获取空手道可执行 jar 文件?
- kubernetes - 为什么叫“容器注册表”?
- spring - 在 Spring 4 中未加载 Log4j2 插件
- javascript - 在 Chrome 扩展程序中,当 URL 的一部分是动态的时,如何为 URL 添加事件侦听器?
- firebase - 如何使用 Go 从我在 firebase 中的实时数据库中获取任何数据
- ffmpeg - FFMPEG 未在 HLS 的输出播放列表文件中写入正确的视频持续时间