discordjs / opus

Native opus bindings for node
MIT License
196 stars 57 forks source link

Buffer #51

Open LuvbCa opened 3 years ago

LuvbCa commented 3 years ago

Please describe the problem you are having in as much detail as possible: When i try to construct the Method OpusEncoder node exits with errno 4294930435 or with Error: Cannot create a Buffer larger than 0x100000000 bytes.

The first one occurs only when rate is set to 32000 on the constructor and the scond on on every other rate

Include a reproducible code sample here, if possible: just construct OpusEncoder.

import Microphone from 'node-microphone'
import { io } from 'socket.io-client'
import { OpusEncoder } from '@discordjs/opus'

const socket = io("http://localhost:3000");
const encoder = new OpusEncoder(16000, 2);

var mic = new Microphone({
    bitwidth: 16,
    channels: 1,
    rate: 32000,
    encoding: 'unsigned-integer',
    endian: 'big'
});

var micStream = mic.startRecording();

micStream.on('data', (data) => {
    var encodedData = encoder.encode(data);
    console.log(encodedData);
    socket.emit('stream', data);
});

Further details: the problem occurs in line 6

mikkeldamsgaard commented 3 years ago

You need to make sure that the length of the argument to encoder.encode() is a multiple of 2.5ms. Since you are encoding with 16000 and two channels (!) that would be multiple of 1622.5 = 80 frames that is 160 bytes. A good normal window size is 20ms, so that would make you have the data buffer at 8*160 bytes exactly.

That said, then the implementation does not check for the return value of int compressedLength = opus_encode(this->encoder, pcm, frameSize, &(this->outOpus[0]), MAX_PACKET_SIZE);. If the data buffer is not exactly aligned it returns -1 which in unsigned form is 0x100000000 and that generates the error as the code tries to allocate a buffer right after this call with the compressedLength.

LuvbCa commented 3 years ago

im currently not working on that project anymore but i will need it in the near future, so im thankful for your answer! i will close this issue when i get to try this!

iocmet commented 2 years ago

You need to make sure that the length of the argument to encoder.encode() is a multiple of 2.5ms. Since you are encoding with 16000 and two channels (!) that would be multiple of 16_2_2.5 = 80 frames that is 160 bytes. A good normal window size is 20ms, so that would make you have the data buffer at 8*160 bytes exactly.

That said, then the implementation does not check for the return value of int compressedLength = opus_encode(this->encoder, pcm, frameSize, &(this->outOpus[0]), MAX_PACKET_SIZE);. If the data buffer is not exactly aligned it returns -1 which in unsigned form is 0x100000000 and that generates the error as the code tries to allocate a buffer right after this call with the compressedLength.

and how i can fix it?

AxioDev commented 1 year ago

Up, thanks for your answer, but can you provide a code example to solve the problem ?

JaderJS commented 2 months ago

Up! Someone who can fix it??

tylerlong commented 2 days ago

I met a similar issue and I found a solution. I am not sure it is a general solution for every one but here I just share it:

If encoder.encode(buffer) throws error: "Error: Cannot create a Buffer larger than 0x100000000 bytes"

Split the buffer into 3840-length smaller buffers, encode then and concat the result.

Sample code:

let result = Buffer.alloc(0)
for(let i = 3840; i <= buffer.length; i +=3840) {
    result = Buffer.concat([result, encoder.encode(buffer.subarray(i - 3840, i))]);
}

The code above is untested. I cannot share my tested code here since it is coupled with other parts of my project.