Discord.js: createOpusStream not valid Opus file

Created on 12 Apr 2018  路  9Comments  路  Source: discordjs/discord.js

Please describe the problem you are having in as much detail as possible:
I'm not able to convert .opus files created by createOpusStream (on stable v11.3.2) using any third party tool (e.g. opusdec and ffmpeg)

Include a reproducible code sample here, if possible:

const receiver = voiceConnection.createReceiver();
voiceConnection.on('speaking', (user, speaking) => {
    if (speaking) {
        const audioStream = receiver.createOpusStream(user);
        const outputStream = fs.createWriteStream('test.opus');
        audioStream.pipe(outputStream);
    }
});

e.g. opusdec test.opus test.wav produces the output This doesn't look like a Opus file

Further details:

  • discord.js version: 11.3.2
  • node.js version: 8.11.1
  • Operating system: Ubuntu 17.10

  • [ ] I found this issue while running code on a __user account__
  • [ ] I have also tested the issue on latest master, commit hash:
voice

Most helpful comment

I hold my hands up, I do see now that the current documentation is lacking in detail and requires some more clarification.

I'm also hoping to an Ogg encoder to prism-media, when that is done I'll maybe write a few examples on how to properly create Opus files.

All 9 comments

Confusingly, I'm pretty sure that .opus files are actually .ogg files with Opus inside, which is why you can't just pipe the stream into a file -- it would only work for playing back in Discord.js.

There are a few tools to help you do this, though, I think node-opus has some support for wrapping the stream in the Ogg container, but I may also add one to prism-media so other people can avoid this.

This isn't _really_ a bug so I'm going to close the issue for now, but thanks for bringing it up.

Ah, so what you're suggesting is that something like opusdec would be expecting an Ogg-wrapped Opus file, whereas the stream is raw Opus? I'll try wrapping the stream and report back

Yep, that should be the issue!

Interesting, I had a look at node-opus for inspiration and I figured the following should work:

const ogg = require('ogg');

const receiver = voiceConnection.createReceiver();
const oggEncoder = new ogg.Encoder();
voiceConnection.on('speaking', (user, speaking) => {
    if (speaking) {
        const audioStream = receiver.createOpusStream(user);
        const outputStream = fs.createWriteStream('test.opus');
        audioStream.pipe(oggEncoder.stream());
        oggEncoder.pipe(outputStream);
    }
});

This actually segfaults, which I guess means that the underlying ogg library doesn't like what's being given to it

The documentation for that module looks like you have to write ogg_packets from an ogg stream encoder, not entirely sure if that's what d.js provides you

Hmm, what does d.js give? I can successfully take a PCM stream -> Opus -> Ogg, but if I could start with the Opus stream then that'd be ideal

Did you manage to fix this? I'm facing the same problem atm.

No, in the end I had to start with a PCM stream and pipe it through both an Opus encoder and an Ogg encoder.

I'm convinced that this is still a legitimate issue: at the very least createOpusStream is violating the principle of least astonishment. Being able to pipe an Opus stream into an Ogg encoder is what you'd expect to be possible, so if any extra processing needs to be done in the middle then it should be well documented (which it wasn't/isn't/isn't clearly explained to non-audio programmers).

I hold my hands up, I do see now that the current documentation is lacking in detail and requires some more clarification.

I'm also hoping to an Ogg encoder to prism-media, when that is done I'll maybe write a few examples on how to properly create Opus files.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  3Comments

iCrawl picture iCrawl  路  3Comments

ghost picture ghost  路  3Comments

LLamaFTL picture LLamaFTL  路  3Comments

shukriadams picture shukriadams  路  3Comments