opus-decoder
Advanced tools
Comparing version 0.3.5 to 0.4.0
{ | ||
"name": "opus-decoder", | ||
"version": "0.3.5", | ||
"version": "0.4.0", | ||
"description": "Web Assembly streaming Opus decoder", | ||
"main": "dist/opus-decoder.min.js", | ||
"module": "index.js", | ||
"type": "module", | ||
"main": "./index.js", | ||
"exports": "./index.js", | ||
"types": "types.d.ts", | ||
@@ -17,7 +18,2 @@ "files": [ | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/eshaz/wasm-audio-decoders.git" | ||
}, | ||
"type": "module", | ||
"keywords": [ | ||
@@ -27,2 +23,4 @@ "Opus", | ||
"decoder", | ||
"multichannel", | ||
"surround", | ||
"stream", | ||
@@ -44,5 +42,14 @@ "streams", | ||
"homepage": "https://github.com/eshaz/wasm-audio-decoders/tree/master/src/opus-decoder", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/eshaz/wasm-audio-decoders.git", | ||
"directory": "src/opus-decoder" | ||
}, | ||
"funding": { | ||
"type": "individual", | ||
"url": "https://github.com/sponsors/eshaz" | ||
}, | ||
"dependencies": { | ||
"@wasm-audio-decoders/common": "1.0.0" | ||
"@wasm-audio-decoders/common": "2.0.0" | ||
} | ||
} |
# `opus-decoder` | ||
`opus-decoder` is a Web Assembly Opus audio decoder. | ||
* 87.7 KiB minified bundle size | ||
* 89.9 KiB minified bundle size | ||
* Browser and NodeJS support | ||
@@ -77,3 +77,2 @@ * Built in Web Worker support | ||
## API | ||
Decoded audio is always returned in the below structure. | ||
@@ -85,3 +84,4 @@ | ||
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 | ||
], | ||
@@ -95,2 +95,19 @@ samplesDecoded: 1234, // number of PCM samples that were decoded per channel | ||
### 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 | ||
Each Float32Array within `channelData` can be used directly in the WebAudio API for playback. | ||
## `OpusDecoder` | ||
@@ -100,2 +117,28 @@ | ||
### Options | ||
```javascript | ||
const decoder = new OpusDecoder({ | ||
preSkip: 0, | ||
channels: 2, | ||
streamCount: 1, | ||
coupledStreamCount: 1, | ||
channelMappingTable: [0, 1] | ||
}); | ||
``` | ||
#### **The below options should be obtained from the Opus Header.** | ||
See this [documentation](https://wiki.xiph.org/OggOpus#ID_Header) on the Opus header for more information. If you don't have access to the Opus header, the default values will successfully decode most stereo Opus streams. | ||
* `preSkip` *optional, defaults to `0`* | ||
* Number of samples to skip at the beginning reported by the Opus header. | ||
#### ***Required for Multichannel Decoding.** (Channel Mapping Family >= 1)* | ||
* `channels` *optional, defaults to `2`* | ||
* Number of channels reported by the Opus header. | ||
* `streamCount` *optional, defaults to `1`* | ||
* Number of streams reported by the Opus header. | ||
* `coupledStreamCount` *optional, defaults to: `1` when 2 channels, `0` when 1 channel* | ||
* Number of coupled streams reported by the Opus header. | ||
* `channelMappingTable` *optional, defaults to `[0, 1]` when 2 channels, `[0]` when 1 channel* | ||
* Channel mapping reported by the Opus header. | ||
### Getters | ||
@@ -123,2 +166,27 @@ * `decoder.ready` *async* | ||
### Options | ||
```javascript | ||
const decoder = new OpusDecoderWebWorker({ | ||
preSkip: 0, | ||
channels: 2, | ||
streamCount: 1, | ||
coupledStreamCount: 1, | ||
channelMappingTable: [0, 1] | ||
}); | ||
``` | ||
#### **The below options should be obtained from the Opus Header.** | ||
See this [documentation](https://wiki.xiph.org/OggOpus#ID_Header) on the Opus header for more information. If you don't have access to the Opus header, the default values will successfully decode most stereo Opus streams. | ||
* `preSkip` *optional, defaults to `0`* | ||
* Number of samples to skip at the beginning reported by the Opus header. | ||
#### ***Required for Multichannel Decoding.** (Channel Mapping Family >= 1)* | ||
* `channels` *optional, defaults to `2`* | ||
* Number of channels reported by the Opus header. | ||
* `streamCount` *optional, defaults to `1`* | ||
* Number of streams reported by the Opus header. | ||
* `coupledStreamCount` *optional, defaults to: `1` when 2 channels, `0` when 1 channel* | ||
* Number of coupled streams reported by the Opus header. | ||
* `channelMappingTable` *optional, defaults to `[0, 1]` when 2 channels, `[0]` when 1 channel* | ||
* Channel mapping reported by the Opus header. | ||
### Getters | ||
@@ -125,0 +193,0 @@ * `decoder.ready` *async* |
@@ -13,7 +13,42 @@ import { WASMAudioDecoderCommon } from "@wasm-audio-decoders/common"; | ||
this._inputPtrSize = (0.12 * 510000) / 8; | ||
const isNumber = (param) => typeof param === "number"; | ||
// channel mapping family >= 1 | ||
if ( | ||
options.channels > 2 && | ||
(!isNumber(options.streamCount) || | ||
!isNumber(options.coupledStreamCount) || | ||
!Array.isArray(options.channelMappingTable)) | ||
) { | ||
throw new Error( | ||
"Invalid Opus Decoder Options for multichannel decoding." | ||
); | ||
} | ||
// channel mapping family 0 | ||
this._channels = isNumber(options.channels) ? options.channels : 2; | ||
this._streamCount = isNumber(options.streamCount) ? options.streamCount : 1; | ||
this._coupledStreamCount = isNumber(options.coupledStreamCount) | ||
? options.coupledStreamCount | ||
: this._channels - 1; | ||
this._channelMappingTable = | ||
options.channelMappingTable || (this._channels === 2 ? [0, 1] : [0]); | ||
this._preSkip = options.preSkip || 0; | ||
this._inputPtrSize = 32000 * 0.12 * this._channels; // 256kbs per channel | ||
this._outputPtrSize = 120 * 48; | ||
this._outputChannels = 2; | ||
this._outputChannels = this._channels; | ||
this._ready = this._init(); | ||
// prettier-ignore | ||
this._errors = { | ||
[-1]: "OPUS_BAD_ARG: One or more invalid/out of range arguments", | ||
[-2]: "OPUS_BUFFER_TOO_SMALL: Not enough bytes allocated in the buffer", | ||
[-3]: "OPUS_INTERNAL_ERROR: An internal error was detected", | ||
[-4]: "OPUS_INVALID_PACKET: The compressed data passed is corrupted", | ||
[-5]: "OPUS_UNIMPLEMENTED: Invalid/unsupported request number", | ||
[-6]: "OPUS_INVALID_STATE: An encoder or decoder structure is invalid or already freed", | ||
[-7]: "OPUS_ALLOC_FAIL: Memory allocation has failed" | ||
} | ||
} | ||
@@ -27,3 +62,15 @@ | ||
this._decoder = this._common.wasm._opus_frame_decoder_create(); | ||
const [mappingPtr, mappingArr] = this._common.allocateTypedArray( | ||
this._channels, | ||
Uint8Array | ||
); | ||
mappingArr.set(this._channelMappingTable); | ||
this._decoder = this._common.wasm._opus_frame_decoder_create( | ||
this._channels, | ||
this._streamCount, | ||
this._coupledStreamCount, | ||
mappingPtr, | ||
this._preSkip | ||
); | ||
} | ||
@@ -46,3 +93,3 @@ | ||
decodeFrame(opusFrame) { | ||
_decode(opusFrame) { | ||
if (!(opusFrame instanceof Uint8Array)) | ||
@@ -63,7 +110,17 @@ throw Error( | ||
return this._WASMAudioDecoderCommon.getDecodedAudio( | ||
[ | ||
this._output.slice(0, samplesDecoded), | ||
this._output.slice(samplesDecoded, samplesDecoded * 2), | ||
], | ||
if (samplesDecoded < 0) { | ||
console.error( | ||
`libopus ${samplesDecoded} ${this._errors[samplesDecoded]}` | ||
); | ||
return 0; | ||
} | ||
return samplesDecoded; | ||
} | ||
decodeFrame(opusFrame) { | ||
const samplesDecoded = this._decode(opusFrame); | ||
return this._WASMAudioDecoderCommon.getDecodedAudioMultiChannel( | ||
this._output, | ||
this._channels, | ||
samplesDecoded, | ||
@@ -75,20 +132,27 @@ 48000 | ||
decodeFrames(opusFrames) { | ||
let left = [], | ||
right = [], | ||
samples = 0; | ||
let outputBuffers = [], | ||
outputSamples = 0; | ||
opusFrames.forEach((frame) => { | ||
const { channelData, samplesDecoded } = this.decodeFrame(frame); | ||
const samplesDecoded = this._decode(frame); | ||
left.push(channelData[0]); | ||
right.push(channelData[1]); | ||
samples += samplesDecoded; | ||
outputBuffers.push( | ||
this._common.getOutputChannels( | ||
this._output, | ||
this._channels, | ||
samplesDecoded | ||
) | ||
); | ||
outputSamples += samplesDecoded; | ||
}); | ||
return this._WASMAudioDecoderCommon.getDecodedAudioConcat( | ||
[left, right], | ||
samples, | ||
const data = this._WASMAudioDecoderCommon.getDecodedAudioMultiChannel( | ||
outputBuffers, | ||
this._channels, | ||
outputSamples, | ||
48000 | ||
); | ||
return data; | ||
} | ||
} |
@@ -1,9 +0,16 @@ | ||
type OpusDecodedAudio = { | ||
channelData: Float32Array[]; | ||
samplesDecoded: number; | ||
sampleRate: 48000; | ||
}; | ||
declare module "opus-decoder" { | ||
export interface OpusDecodedAudio { | ||
channelData: Float32Array[]; | ||
samplesDecoded: number; | ||
sampleRate: 48000; | ||
} | ||
declare module 'opus-decoder' { | ||
export class OpusDecoder { | ||
constructor(options?: { | ||
preSkip?: number; | ||
channels?: number; | ||
streamCount?: number; | ||
coupledStreamCount?: number; | ||
channelMappingTable?: number[]; | ||
}); | ||
ready: Promise<void>; | ||
@@ -17,2 +24,9 @@ reset: () => Promise<void>; | ||
export class OpusDecoderWebWorker { | ||
constructor(options?: { | ||
preSkip?: number; | ||
channels?: number; | ||
streamCount?: number; | ||
coupledStreamCount?: number; | ||
channelMappingTable?: number[]; | ||
}); | ||
ready: Promise<void>; | ||
@@ -19,0 +33,0 @@ reset: () => Promise<void>; |
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
210273
941
234
+ Added@wasm-audio-decoders/common@2.0.0(transitive)
- Removed@wasm-audio-decoders/common@1.0.0(transitive)