ogg-opus-decoder
Advanced tools
Comparing version 1.2.4 to 1.3.0
{ | ||
"name": "ogg-opus-decoder", | ||
"version": "1.2.4", | ||
"version": "1.3.0", | ||
"description": "Web Assembly streaming Ogg Opus decoder", | ||
@@ -26,2 +26,4 @@ "main": "dist/ogg-opus-decoder.min.js", | ||
"decoder", | ||
"multichannel", | ||
"surround", | ||
"stream", | ||
@@ -46,4 +48,4 @@ "streams", | ||
"dependencies": { | ||
"@wasm-audio-decoders/common": "0.0.1" | ||
"@wasm-audio-decoders/common": "1.0.0" | ||
} | ||
} |
@@ -7,2 +7,3 @@ # `ogg-opus-decoder` | ||
* Built in Web Worker support | ||
* Multichannel decoding (up to 8 channels) | ||
* Based on [`libopusfile`](https://github.com/xiph/opusfile) | ||
@@ -84,5 +85,6 @@ | ||
leftAudio, // Float32Array of PCM samples for the left channel | ||
rightAudio // Float32Array of PCM samples for the right channel | ||
rightAudio, // Float32Array of PCM samples for the right channel | ||
... // additional channels | ||
], | ||
samplesDecoded: 1234, // number of PCM samples that were decoded | ||
samplesDecoded: 1234, // number of PCM samples that were decoded per channel | ||
sampleRate: 48000 // sample rate of the decoded PCM | ||
@@ -94,2 +96,17 @@ } | ||
### Multichannel Output | ||
Each channel is assigned to a speaker location in a conventional surround arrangement. Specific locations depend on the number of channels, and are given below in order of the corresponding channel indices. This set of surround options and speaker location orderings is the same as those used by the Vorbis codec. | ||
* 1 channel: monophonic (mono). | ||
* 2 channels: stereo (left, right). | ||
* 3 channels: linear surround (left, center, right). | ||
* 4 channels: quadraphonic (front left, front right, rear left, rear right). | ||
* 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right). | ||
* 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE). | ||
* 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE). | ||
* 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE). | ||
See: https://datatracker.ietf.org/doc/html/rfc7845.html#section-5.1.1.2 | ||
## `OggOpusDecoder` | ||
@@ -99,2 +116,10 @@ | ||
### Options | ||
```javascript | ||
const decoder = new OggOpusDecoder({ forceStereo: true }); | ||
``` | ||
* `forceStereo` *optional, defaults to `false`* | ||
* Set to `true` to forces stereo output when decoding mono or multichannel Ogg Opus. | ||
### Getters | ||
@@ -119,2 +144,10 @@ * `decoder.ready` *async* | ||
### Options | ||
```javascript | ||
const decoder = new OggOpusDecoderWebWorker({ forceStereo: true }); | ||
``` | ||
* `forceStereo` *optional, defaults to `false`* | ||
* Set to `true` to forces stereo output when decoding mono or multichannel Ogg Opus. | ||
### Getters | ||
@@ -121,0 +154,0 @@ * `decoder.ready` *async* |
@@ -6,16 +6,36 @@ import { WASMAudioDecoderCommon } from "@wasm-audio-decoders/common"; | ||
export default class OggOpusDecoder { | ||
constructor(_WASMAudioDecoderCommon, _EmscriptenWASM) { | ||
constructor(options = {}) { | ||
// injects dependencies when running as a web worker | ||
this._isWebWorker = _WASMAudioDecoderCommon && _EmscriptenWASM; | ||
this._isWebWorker = this.constructor.isWebWorker; | ||
this._WASMAudioDecoderCommon = | ||
_WASMAudioDecoderCommon || WASMAudioDecoderCommon; | ||
this._EmscriptenWASM = _EmscriptenWASM || EmscriptenWASM; | ||
this.constructor.WASMAudioDecoderCommon || WASMAudioDecoderCommon; | ||
this._EmscriptenWASM = this.constructor.EmscriptenWASM || EmscriptenWASM; | ||
this._stereoDownmix = options.stereoDownmix || false; | ||
// Max data to send per iteration. 64k is the max for enqueueing in libopusfile. | ||
this._inputPtrSize = 64 * 1024; | ||
// 120ms buffer recommended per http://opus-codec.org/docs/opusfile_api-0.7/group__stream__decoding.html | ||
// per channel | ||
this._outputPtrSize = 120 * 48; // 120ms @ 48 khz. | ||
this._channelsOut = 2; | ||
this._outputChannels = 8; // max opus output channels | ||
this._ready = this._init(); | ||
// prettier-ignore | ||
this._errors = { | ||
[-1]: "OP_FALSE: A request did not succeed.", | ||
[-3]: "OP_HOLE: There was a hole in the page sequence numbers (e.g., a page was corrupt or missing).", | ||
[-128]: "OP_EREAD: An underlying read, seek, or tell operation failed when it should have succeeded.", | ||
[-129]: "OP_EFAULT: A NULL pointer was passed where one was unexpected, or an internal memory allocation failed, or an internal library error was encountered.", | ||
[-130]: "OP_EIMPL: The stream used a feature that is not implemented, such as an unsupported channel family.", | ||
[-131]: "OP_EINVAL: One or more parameters to a function were invalid.", | ||
[-132]: "OP_ENOTFORMAT: A purported Ogg Opus stream did not begin with an Ogg page, a purported header packet did not start with one of the required strings, \"OpusHead\" or \"OpusTags\", or a link in a chained file was encountered that did not contain any logical Opus streams.", | ||
[-133]: "OP_EBADHEADER: A required header packet was not properly formatted, contained illegal values, or was missing altogether.", | ||
[-134]: "OP_EVERSION: The ID header contained an unrecognized version number.", | ||
[-136]: "OP_EBADPACKET: An audio packet failed to decode properly. This is usually caused by a multistream Ogg packet where the durations of the individual Opus packets contained in it are not all the same.", | ||
[-137]: "OP_EBADLINK: We failed to find data we had seen before, or the bitstream structure was sufficiently malformed that seeking to the target destination was impossible.", | ||
[-138]: "OP_ENOSEEK: An operation that requires seeking was requested on an unseekable stream.", | ||
[-139]: "OP_EBADTIMESTAMP: The first or last granule position of a link failed basic validity checks.", | ||
} | ||
} | ||
@@ -28,3 +48,9 @@ | ||
[this._channelsDecodedPtr, this._channelsDecoded] = | ||
this._common.allocateTypedArray(1, Uint32Array); | ||
this._decoder = this._common.wasm._ogg_opus_decoder_create(); | ||
this._decoderMethod = this._stereoDownmix | ||
? this._common.wasm._ogg_opus_decode_float_stereo_deinterleaved | ||
: this._common.wasm._ogg_opus_decode_float_deinterleaved; | ||
} | ||
@@ -56,72 +82,65 @@ | ||
let decodedLeft = [], | ||
decodedRight = [], | ||
let output = [], | ||
decodedSamples = 0, | ||
offset = 0; | ||
while (offset < data.length) { | ||
const dataToSend = data.subarray( | ||
offset, | ||
offset + Math.min(this._inputPtrSize, data.length - offset) | ||
); | ||
try { | ||
while (offset < data.length) { | ||
const dataToSend = data.subarray( | ||
offset, | ||
offset + Math.min(this._inputPtrSize, data.length - offset) | ||
); | ||
offset += dataToSend.length; | ||
offset += dataToSend.length; | ||
this._input.set(dataToSend); | ||
this._input.set(dataToSend); | ||
// enqueue bytes to decode. Fail on error | ||
if ( | ||
!this._common.wasm._ogg_opus_decoder_enqueue( | ||
const enqueueResult = this._common.wasm._ogg_opus_decoder_enqueue( | ||
this._decoder, | ||
this._inputPtr, | ||
dataToSend.length | ||
) | ||
) | ||
throw Error( | ||
"Could not enqueue bytes for decoding. You may also have invalid Ogg Opus file." | ||
); | ||
// continue to decode until no more bytes are left to decode | ||
let samplesDecoded; | ||
while ( | ||
(samplesDecoded = | ||
this._common.wasm._ogg_opus_decode_float_stereo_deinterleaved( | ||
if (enqueueResult) | ||
throw { | ||
code: enqueueResult, | ||
message: "Failed to enqueue bytes for decoding.", | ||
}; | ||
// continue to decode until no more bytes are left to decode | ||
let samplesDecoded; | ||
while ( | ||
(samplesDecoded = this._decoderMethod( | ||
this._decoder, | ||
this._leftPtr, // left channel | ||
this._rightPtr // right channel | ||
this._channelsDecodedPtr, | ||
this._outputPtr | ||
)) > 0 | ||
) { | ||
decodedLeft.push(this._leftArr.slice(0, samplesDecoded)); | ||
decodedRight.push(this._rightArr.slice(0, samplesDecoded)); | ||
decodedSamples += samplesDecoded; | ||
} | ||
) { | ||
output.push( | ||
this._common.getOutputChannels( | ||
this._output, | ||
this._channelsDecoded[0], | ||
samplesDecoded | ||
) | ||
); | ||
// prettier-ignore | ||
if (samplesDecoded < 0) { | ||
const errors = { | ||
[-1]: "A request did not succeed.", | ||
[-3]: "There was a hole in the page sequence numbers (e.g., a page was corrupt or missing).", | ||
[-128]: "An underlying read, seek, or tell operation failed when it should have succeeded.", | ||
[-129]: "A NULL pointer was passed where one was unexpected, or an internal memory allocation failed, or an internal library error was encountered.", | ||
[-130]: "The stream used a feature that is not implemented, such as an unsupported channel family.", | ||
[-131]: "One or more parameters to a function were invalid.", | ||
[-132]: "A purported Ogg Opus stream did not begin with an Ogg page, a purported header packet did not start with one of the required strings, \"OpusHead\" or \"OpusTags\", or a link in a chained file was encountered that did not contain any logical Opus streams.", | ||
[-133]: "A required header packet was not properly formatted, contained illegal values, or was missing altogether.", | ||
[-134]: "The ID header contained an unrecognized version number.", | ||
[-136]: "An audio packet failed to decode properly. This is usually caused by a multistream Ogg packet where the durations of the individual Opus packets contained in it are not all the same.", | ||
[-137]: "We failed to find data we had seen before, or the bitstream structure was sufficiently malformed that seeking to the target destination was impossible.", | ||
[-138]: "An operation that requires seeking was requested on an unseekable stream.", | ||
[-139]: "The first or last granule position of a link failed basic validity checks.", | ||
decodedSamples += samplesDecoded; | ||
} | ||
if (samplesDecoded < 0) | ||
throw { code: samplesDecoded, message: "Failed to decode." }; | ||
} | ||
} catch (e) { | ||
if (e.code) | ||
throw new Error( | ||
`libopusfile ${samplesDecoded}: ${ | ||
errors[samplesDecoded] || "Unknown Error" | ||
`${e.message} libopusfile ${e.code} ${ | ||
this._errors[e.code] || "Unknown Error" | ||
}` | ||
); | ||
} | ||
throw e; | ||
} | ||
return this._WASMAudioDecoderCommon.getDecodedAudioConcat( | ||
[decodedLeft, decodedRight], | ||
return this._WASMAudioDecoderCommon.getDecodedAudioMultiChannel( | ||
output, | ||
this._channelsDecoded[0], | ||
decodedSamples, | ||
@@ -128,0 +147,0 @@ 48000 |
@@ -6,4 +6,4 @@ import { WASMAudioDecoderWorker } from "@wasm-audio-decoders/common"; | ||
export default class OggOpusDecoderWebWorker extends WASMAudioDecoderWorker { | ||
constructor() { | ||
super(OggOpusDecoder, EmscriptenWASM); | ||
constructor(options) { | ||
super(options, OggOpusDecoder, EmscriptenWASM); | ||
} | ||
@@ -10,0 +10,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
High entropy strings
Supply chain riskContains high entropy strings. This could be a sign of encrypted data, leaked secrets or obfuscated code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
High entropy strings
Supply chain riskContains high entropy strings. This could be a sign of encrypted data, leaked secrets or obfuscated code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
264936
1119
257
+ Added@wasm-audio-decoders/common@1.0.0(transitive)
- Removed@wasm-audio-decoders/common@0.0.1(transitive)