native-bindings / libopus

3 stars 0 forks source link

Segmentation fault #1

Open MatthD opened 1 year ago

MatthD commented 1 year ago

First thanks for your library wich is really well written! 😎

I tested some project to benchmark resampler of audio file. With node-opushenc I am facing segmentation fault issue with this code .

I am loading a wav file and just try to send it via sox to the stdout to parse the data and then just change the sample rate from 44100 to 16000hz If you have better and safer idea, let me know :)

// https://github.com/victorqueiroz/node-opusenc
import opus from "libopus";
import { spawn } from "child_process";
import { resolve } from "path";
import "dotenv/config";

console.log(process.env.LARGE_WAV_PATH);

const comments = new opus.opusenc.Comments();
const enc = new opus.opusenc.Encoder();
enc.createFile(
  comments,
  resolve(__dirname, "../output/output-libopus-js.ogg"),
  16000,
  2,
  0
);
const pcm = spawn("sox", [
  process.env.LARGE_WAV_PATH ||
    "/Users/dieudonn/Downloads/large-sample-usa.wav",
  "-t",
  "wav",
  "-",
]);
console.log("Start converting sample rate...");
pcm.stdout.on("data", (chunk) => {
  const samples = Math.floor(chunk.byteLength / Float32Array.BYTES_PER_ELEMENT);
  const buf = new Float32Array(samples);
  buf.set(new Float32Array(chunk.buffer, chunk.byteOffset, samples));
  enc.writeFloat(buf, samples);
});
new Promise<void>((resolve) => {
  pcm.stdout.on("exit", (code) => {
    console.log("Finished converting file");
    enc.drain();
    resolve();
  });
});

Capture d’écran 2023-10-12 à 10 06 54

VictorQueiroz commented 1 year ago

Hey @MatthD, I am super glad you liked it. I appreciate it. It was so much fun to develop these bindings.

About the problem you are facing, I am very sorry. I understand it must be frustrating.

Can you please find out what call in your JavaScript code is causing the segmentation fault? Also, you need to call getPage(true) after you call writeFloat so you can get the opus file header and pages.

Another thing I want to point out is that you must make sure that whatever sox is outputting ranges of the audio (i.e. 100 ms, 200 ms, etc) in 32-bit floating-point integer little-endian format, because that's what libopusenc expects.

My guess is that you are providing invalid data to writeFloat call, which is causing it to read data outside of the range of the provided buffer, thus, causing the seg fault.

My guess is based on the fact (IIRC) that you should not need Math.floor to get the sample count, it must return an exact number when you divide it by Float32Array.BYTES_PER_ELEMENT.

About the sample rate change, if you use the opusenc implementation, it uses speexdsp resampler under the hood, so it will take any input sample rate, and output an acceptable sample rate for libopus.