Please describe the problem you are having in as much detail as possible:
It looks like a change happened with voice packets and it seems they cannot be decoded. Voice packets are still being sent, but when attempting to convert them, or even change the receiver to PCM instead of Opus, they become corrupt. I cannot decode the frames with Opusdec either. Below is code I used for v12 to make a quick idea of whats happening.
Include a reproducible code sample here, if possible:
require("dotenv").config();
const { CLIENT_TOKEN } = process.env;
const { Client } = require("discord.js");
const Silence = require("./Silence");
const client = new Client();
client.on("ready", () => {
console.log("ready");
let voiceChannel = client.channels.get("channel-id-here");
voiceChannel.join().then(connection => {
connection.play(new Silence(), { type: "opus" });
connection.on("speaking", (user, speaking) => {
let chunks = [];
if (speaking.bitfield === 1) {
const receiver = connection.receiver.createStream(user, { mode: "pcm", end: "silence" });
receiver.on("data", chunk => {
chunks.push(chunk);
});
}
});
}).catch(console.error);
});
client.login(CLIENT_TOKEN);
--------------------------
Console:
ready
/home/john/testing/node_modules/prism-media/src/opus/Opus.js:58
return this.encoder.decode(buffer, Opus.name !== 'node-opus' ? this._options.frameSize : null);
^
TypeError: The compressed data passed is corrupted
at Decoder._decode (/home/john/testing/node_modules/prism-media/src/opus/Opus.js:58:25)
at Decoder._transform (/home/john/testing/node_modules/prism-media/src/opus/Opus.js:183:20)
at Decoder.Transform._read (_stream_transform.js:190:10)
at Decoder.Transform._write (_stream_transform.js:178:12)
at doWrite (_stream_writable.js:410:12)
at writeOrBuffer (_stream_writable.js:394:5)
at Decoder.Writable.write (_stream_writable.js:294:11)
at Readable.ondata (_stream_readable.js:689:20)
at Readable.emit (events.js:189:13)
at addChunk (_stream_readable.js:284:12)
at readableAddChunk (_stream_readable.js:265:11)
at Readable.push (_stream_readable.js:220:10)
at PacketHandler.push (/home/john/testing/node_modules/discord.js/src/client/voice/receiver/PacketHandler.js:87:12)
at Socket.socket.on.buffer (/home/john/testing/node_modules/discord.js/src/client/voice/networking/VoiceUDPClient.js:131:76)
at Socket.emit (events.js:189:13)
at UDP.onMessage [as onmessage] (dgram.js:628:8)
--------------------------
Further details:
I'm getting the same bug on Stable
I'm getting a similar issue, I have just updated to the latest build. I'm not sure if it was happening before that (a build several months old), but I suspect it was, so maybe a change on the discord end.
This seems to be happening with my bot as well (on stable). I've tried streaming the audio back to discord and playing it in a voice channel but the sound just comes out like someone is pouring water. lol :-) . I don't get any errors but I'm guessing the packets could be corrupted as E0HH said?
Please note that Discord does not support receiving audio, so while we can do our best to support it within the library, it is likely to break. In this case, Discord must have made some breaking changes.
Thanks @amishshah, that explains a lot in my (unsuccessful) search through their docs for the current API version and what may have changed! :/
This is the Discord feature request: https://github.com/discordapp/discord-api-docs/issues/365 - I'm assuming (hoping) the more +1 they get the more likely they are to do something about it, so if everyone can please click on it that would be great.
Yeah I can unfortunately confirm this it seems like. After fixing the fact that speaking updates no longer came through properly, I encountered this next. I can still decode the packages to PCM occasionally, but it all comes out as corrupted noise when played back
I figured it out! For the latest master:
In "src/client/voice/receiver/PacketHandler.js" at L66
Replace:
while (packet[offset] === 0) offset++;
With:
offset++;
Explanation:
As far as I can tell the point of that while loop was to go past all empty bytes that might be between the end of the RTP headers and the Opus packet. Since we have no discord documentation on this we don't really know what these bytes do officially.
I assume the assumption was that this was just padding, since every packet used to have one zero byte there. However as it turns out that is no longer the case! This byte in question is now 0x02 for most regular packages and 0 for empty/silent packages as far as I can tell.
So instead of padding it is probably some additional information byte for the discord client, which previously wasn't used and was merely a placeholder, but now is used.
Just reading over it seems to work out fine for now. With the old code it would read over the byte correctly if it was 0, but not if it was 2, which is now the case for most voice packages. This made Opus incorrectly interpret the 0x02 as the TOC byte, which doesn't really make sense. Reading up on the Opus TOC byte made me realize this error.
@dragonbane0 how and why are you so smart!? This makes two annoying problems you've solved for me now. Thanks :-). Anyway, for anyone wanting to fix this problem on stable instead of master, follow the instructions of @dragonbane0 above, but instead of editing src/client/voice/receiver/PacketHandler.js, edit src/client/voice/receiver/VoiceReceiver.js. The broken code is also on line 177 in stable instead of line 66 in the master branch.
Fantastic work @dragonbane0 you sir are a legend. Would of never caught that. Hydra, should someone create a pull request for the change? Code is now working for me on master with the fix above.
Great find @dragonbane0! Do you want to make a PR for it? :)
@amishshah sure! Will get on it in a bit
Help me pls:v
2020-07-08T04:13:34.473464+00:00 app[worker.1]: Uncaught Exception: TypeError: The compressed data passed is corrupted
2020-07-08T04:13:34.473484+00:00 app[worker.1]: at Decoder._decode (/app/node_modules/prism-media/src/opus/Opus.js:64:25)
2020-07-08T04:13:34.473485+00:00 app[worker.1]: at Decoder._transform (/app/node_modules/prism-media/src/opus/Opus.js:189:20)
2020-07-08T04:13:34.473486+00:00 app[worker.1]: at Decoder.Transform._read (_stream_transform.js:191:10)
2020-07-08T04:13:34.473487+00:00 app[worker.1]: at Decoder.Transform._write (_stream_transform.js:179:12)
2020-07-08T04:13:34.473488+00:00 app[worker.1]: at doWrite (_stream_writable.js:403:12)
2020-07-08T04:13:34.473488+00:00 app[worker.1]: at writeOrBuffer (_stream_writable.js:387:5)
2020-07-08T04:13:34.473488+00:00 app[worker.1]: at Decoder.Writable.write (_stream_writable.js:318:11)
2020-07-08T04:13:34.473489+00:00 app[worker.1]: at Socket.ondata (_stream_readable.js:717:22)
2020-07-08T04:13:34.473489+00:00 app[worker.1]: at Socket.emit (events.js:315:20)
2020-07-08T04:13:34.473490+00:00 app[worker.1]: at addChunk (_stream_readable.js:295:12)
I got the same error, that's weird what happens these days 😔
@MTGPROD @Ettokun I have just tested with the latest build using my example here: https://github.com/sillyfrog/discord.js-listenexample and things are working as expected. So maybe there is some other library conflict causing issues? I would suggest starting with that example (in Docker) and seeing if you can reproduce from there.
Remember also that the receive API is not an official one from Discord, so it could change at any time.
Most helpful comment
I figured it out! For the latest master:
In "src/client/voice/receiver/PacketHandler.js" at L66
Replace:
while (packet[offset] === 0) offset++;With:
offset++;Explanation:
As far as I can tell the point of that while loop was to go past all empty bytes that might be between the end of the RTP headers and the Opus packet. Since we have no discord documentation on this we don't really know what these bytes do officially.
I assume the assumption was that this was just padding, since every packet used to have one zero byte there. However as it turns out that is no longer the case! This byte in question is now 0x02 for most regular packages and 0 for empty/silent packages as far as I can tell.
So instead of padding it is probably some additional information byte for the discord client, which previously wasn't used and was merely a placeholder, but now is used.
Just reading over it seems to work out fine for now. With the old code it would read over the byte correctly if it was 0, but not if it was 2, which is now the case for most voice packages. This made Opus incorrectly interpret the 0x02 as the TOC byte, which doesn't really make sense. Reading up on the Opus TOC byte made me realize this error.