npm install @native-bindings/libopus
Entirely synchronous API to create .ogg files encoded using libopus library. It supports several sample rates (16000,48000 and more.).
Below it's an example on how to use the opus codec by itself, without interference of the libopusenc. AFAIK, the encoded data cannot be directly placed in a .ogg file for playing. If you need that, see the next example.
importopusfrom"@native-bindings/libopus";exportfunctioncreateTestCodec(){constframeSize=2880;constsampleRate=48000;constchannels=1;constenc=newopus.Encoder(sampleRate,channels,opus.constants.OPUS_APPLICATION_RESTRICTED_LOWDELAY);constdec=newopus.Decoder(sampleRate,channels);constpcmOut=newFloat32Array(frameSize*channels*Float32Array.BYTES_PER_ELEMENT);constencoded=newUint8Array(10000);constmaxDataBytes=1000;// it can be increased up to whatever `encoded` size isconstencodeFloat=(buf: Float32Array)=>{constencodedSampleCount=enc.encodeFloat(buf,frameSize,encoded,maxDataBytes);console.log("encoded samples: %d",encodedSampleCount);returnencodedSampleCount;};constdecodeFloat=(buf: Uint8Array,samples: number)=>{constdecodedSamples=dec.decodeFloat(buf,samples,pcmOut,frameSize,0);returnnewUint8Array(pcmOut.slice(0,decodedSamples).buffer);};constencodeAndDecode=(buf: Float32Array)=>{constencodedSampleCount=encodeFloat(buf);returndecodeFloat(encoded,encodedSampleCount);};return{
decode,
encode,
encodeAndDecode,};}This package comes with libopusenc embedded in it, so you can create .ogg/.opus files directly with it with any sample rate. It will use speexdsp in case a sample rate that is not supported by libopus is used when creating the encoder. See the example below:
importopusfrom"@native-bindings/libopus";constcomments=newopus.opusenc.Comments();constenc=newopus.opusenc.Encoder();enc.createFile(comments,path.resolve(__dirname,"test1.ogg"),48000,1,0);constpcm=child_process.spawn("arecord",["-f","FLOAT_LE","-c","1","-r","48000","-d","4",]);pcm.stdout.on("data",(chunk)=>{assert.strict.ok(Buffer.isBuffer(chunk));constsamples=chunk.byteLength/Float32Array.BYTES_PER_ELEMENT;constbuf=newFloat32Array(samples);buf.set(newFloat32Array(chunk.buffer,chunk.byteOffset,samples));enc.writeFloat(buf,samples);});returnnewPromise<void>((resolve)=>{pcm.stdout.on("exit",(code)=>{assert.strict.ok(code===0);enc.drain();resolve();});});import{OpusFile}from"@native-bindings/libopus";constof=newOpusFile();of.openFile(path.resolve(__dirname,"sample-3.opus"));constpcm=newFloat32Array(2880);assert.strict.equal(of.pcmTell(),0);assert.strict.deepEqual(of.readFloat(pcm),{sampleCount: 648,linkIndex: 0,});assert.strict.deepEqual(of.pcmTell(),648);assert.strict.deepEqual(of.readFloat(pcm),{sampleCount: 960,linkIndex: 0,});assert.strict.equal(of.pcmTell(),1608);assert.strict.equal(of.pcmSeek(0),undefined);assert.strict.equal(of.pcmTell(),0);assert.strict.deepEqual(of.readFloat(pcm),{sampleCount: 648,linkIndex: 0,});assert.strict.equal(of.channelCount(0),2);assert.strict.equal(of.channelCount(1),2);assert.strict.equal(of.linkCount(),1);assert.strict.equal(of.rawTotal(0),705632);You can also open the file from memory:
import{OpusFile}from"@native-bindings/libopus";constof=newOpusFile();of.openMemory(awaitfs.promises.readFile("./sample.opus"));