opus-decoder
opus-decoder
is a Web Assembly Opus audio decoder.
- 85.0 KiB minified bundle size
- Browser and NodeJS support
- Built in Web Worker support
- Based on
libopus
This library is intended for users that already have Opus frames extracted from a container, i.e. (Ogg, Matroska (WEBM), or ISOBMFF (mp4)). See ogg-opus-decoder
if you have an Ogg Opus file to decode.
See the homepage of this repository for more Web Assembly audio decoders like this one.
Installing
-
Install from NPM.
Run npm i opus-decoder
import { OpusDecoder } from 'opus-decoder';
const decoder = new OpusDecoder();
-
Or download the build and include it as a script.
<script src="opus-decoder.min.js"></script>
<script>
const decoder = new window["opus-decoder"].OpusDecoder();
</script>
Usage
-
Create a new instance and wait for the WASM to finish compiling. Decoding can be done on the main thread synchronously, or in a webworker asynchronously.
Main thread synchronous decoding
import { OpusDecoder } from 'opus-decoder';
const decoder = new OpusDecoder();
await decoder.ready;
Web Worker asynchronous decoding
import { OpusDecoderWebWorker } from 'opus-decoder';
const decoder = new OpusDecoderWebWorker();
await decoder.ready;
-
Begin decoding Opus frames.
const {channelData, samplesDecoded, sampleRate} = decoder.decodeFrame(opusFrame);
const {channelData, samplesDecoded, sampleRate} = decoder.decodeFrames(opusFrameArray);
-
When done decoding, reset the decoder to decode a new stream, or free up the memory being used by the WASM module if you have no more audio to decode.
await decoder.reset();
decoder.free();
API
Decoded audio is always returned in the below structure.
{
channelData: [
leftAudio,
rightAudio,
...
],
samplesDecoded: 1234,
sampleRate: 48000,
errors: [
{
message: "libopus -4 OPUS_INVALID_PACKET: The compressed data passed is corrupted",
frameLength: 400,
frameNumber: 21,
inputBytes: 4905,
outputSamples: 18888,
}
]
}
Each Float32Array within channelData
can be used directly in the WebAudio API for playback.
Decoding will proceed through any errors. Any errors encountered may result in gaps in the decoded audio.
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).
- 9-255 channels: No mapping is defined.
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
Class that decodes Opus frames synchronously on the main thread.
Options
const decoder = new OpusDecoder({
forceStereo: false,
sampleRate: 48000,
preSkip: 0,
channels: 2,
streamCount: 1,
coupledStreamCount: 1,
channelMappingTable: [0, 1]
});
See this documentation 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.
forceStereo
optional, defaults to false
- Set to
true
to force stereo output when decoding mono or multichannel Ogg Opus. - If there are more than 8 channels, this option is ignored.
preSkip
optional, defaults to 0
- Number of samples to skip at the beginning reported by the Opus header.
sampleRate
optional, defaults to 48000
- Sample rate the decoder will output.
- Valid sample rates:
8000, 12000, 16000, 24000, or 48000
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
decoder.ready
async
- Returns a promise that is resolved when the WASM is compiled and ready to use.
Methods
decoder.decodeFrame(opusFrame)
opusFrame
Uint8Array containing a single Opus frame.- Returns decoded audio.
decoder.decodeFrames(opusFrames)
opusFrames
Array of Uint8Arrays containing Opus frames.- Returns decoded audio.
decoder.reset()
async
- Resets the decoder so that a new stream of Opus frames can be decoded.
decoder.free()
- De-allocates the memory used by the decoder.
- After calling
free()
, the current instance is made unusable, and a new instance will need to be created to decode additional Opus frames.
OpusDecoderWebWorker
Class that decodes Opus frames asynchronously within a web worker. Decoding is performed in a separate, non-blocking thread. Each new instance spawns a new worker allowing you to run multiple workers for concurrent decoding of multiple streams.
Options
const decoder = new OpusDecoderWebWorker({
forceStereo: false,
channels: 2,
streamCount: 1,
coupledStreamCount: 1,
channelMappingTable: [0, 1]
});
See this documentation 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.
forceStereo
optional, defaults to false
- Set to
true
to force stereo output when decoding mono or multichannel Ogg Opus. - If there are more than 8 channels, this option is ignored.
preSkip
optional, defaults to 0
- Number of samples to skip at the beginning reported by the Opus header.
sampleRate
optional, defaults to 48000
- Sample rate the decoder will output.
- Valid sample rates:
8000, 12000, 16000, 24000, or 48000
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
decoder.ready
async
- Returns a promise that is resolved when the WASM is compiled and ready to use.
Methods
decoder.decodeFrame(opusFrame)
async
opusFrame
Uint8Array containing a single Opus frame.- Returns a promise that resolves with the decoded audio.
decoder.decodeFrames(opusFrames)
async
opusFrames
Array of Uint8Arrays containing Opus frames.- Returns a promise that resolves with the decoded audio.
decoder.reset()
async
- Resets the decoder so that a new stream of Opus frames can be decoded.
decoder.free()
async
- De-allocates the memory used by the decoder and terminates the web worker.
- After calling
free()
, the current instance is made unusable, and a new instance will need to be created to decode additional Opus frames.
Properly using the Web Worker interface
OpusDecoderWebWorker
uses async functions to send operations to the web worker without blocking the main thread. To fully take advantage of the concurrency provided by web workers, your code should avoid using await
on decode operations where it will block the main thread.
Each method call on a OpusDecoderWebWorker
instance will queue up an operation to the web worker. Operations will complete within the web worker thread one at a time and in the same order in which the methods were called.
-
Good Main thread is not blocked during each decode operation. The example playAudio
function is called when each decode operation completes. Also, the next decode operation can begin while playAudio
is doing work on the main thread.
const playAudio = ({ channelData, samplesDecoded, sampleRate }) => {
}
decoder.decodeFrame(frameData1).then(playAudio);
decoder.decodeFrame(frameData2).then(playAudio);
decoder.decodeFrame(frameData3).then(playAudio);
-
Bad Main thread is being blocked by await
during each decode operation. Synchronous code is halted while decoding completes, negating the benefits of using a webworker.
const decoded1 = await decoder.decodeFrame(frameData1);
playAudio(decoded1);
const decoded2 = await decoder.decodeFrame(frameData2);
playAudio(decoded2);
const decoded3 = await decoder.decodeFrame(frameData3);
playAudio(decoded3);