JSPM

  • Created
  • Published
  • Downloads 342975
  • Score
    100M100P100Q283203F
  • License MIT

Web Assembly streaming Ogg Opus decoder

Package Exports

  • ogg-opus-decoder

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ogg-opus-decoder) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

ogg-opus-decoder

ogg-opus-decoder is a Web Assembly Ogg Opus audio decoder.

  • 115.1 KiB minified bundle size
  • Built in Web Worker support
  • Based on libopusfile

See the homepage of this repository for more Web Assembly audio decoders like this one.

Installing

  • Install from NPM.

    Run npm i mpg123-decoder

    import { OggOpusDecoder } from 'ogg-opus-decoder';
    
    const decoder = new OggOpusDecoder();
  • Or download the build and include it as a script.

    <script src="ogg-opus-decoder.min.js"></script>
    <script>
      const decoder = new OggOpusDecoder();
    </script>

Usage

  1. 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 { OggOpusDecoder } from 'ogg-opus-decoder';
    
    const decoder = new OggOpusDecoder();
    
    // wait for the WASM to be compiled
    await decoder.ready;

    Web Worker asynchronous decoding

    import { OggOpusDecoderWebWorker } from 'ogg-opus-decoder';
    
    const decoder = new OggOpusDecoderWebWorker();
    
    // wait for the WASM to be compiled
    await decoder.ready;
  2. Begin decoding Ogg Opus data.

    // Decode an individual Opus frame
    const {channelData, samplesDecoded, sampleRate} = decoder.decode(oggOpusData);
    • NOTE: When decoding chained Ogg files (i.e. streaming) the first two Ogg packets of the next chain must be present when decoding. Errors will be returned by libopusfile if these initial Ogg packets are incomplete.
  3. 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.

    // `reset()` clears the decoder state and allows you do decode a new stream of Ogg Opus data.
    decoder.reset();
    
    // `free()` de-allocates the memory used by the decoder. You will need to create a new instance after calling `free()` to start decoding again.
    decoder.free();

API

Decoded audio is always returned in the below structure.

{
    channelData: [
      leftAudio, // Float32Array of PCM samples for the left channel
      rightAudio // Float32Array of PCM samples for the right channel
    ],
    samplesDecoded: 1234, // number of PCM samples that were decoded
    sampleRate: 48000 // sample rate of the decoded PCM
}

Each Float32Array within channelData can be used directly in the WebAudio API for playback.

OggOpusDecoder

Class that decodes Ogg Opus data synchronously on the main thread.

Getters

  • decoder.ready async
    • Returns a promise that is resolved when the WASM is compiled and ready to use.

Methods

  • decoder.decode(oggOpusData)
    • opusFrame Uint8Array containing Ogg Opus data.
    • Returns decoded audio.
  • decoder.reset() async
    • Resets the decoder so that a new stream of Ogg Opus data 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 Ogg Opus data.

OggOpusDecoderWebWorker

Class that decodes Ogg Opus data 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.

Getters

  • decoder.ready async
    • Returns a promise that is resolved when the WASM is compiled and ready to use.

Methods

  • decoder.decode(oggOpusData) *Async
    • opusFrame Uint8Array containing Ogg Opus data.
    • Returns a promise that resolves with the decoded audio.
  • decoder.reset() async
    • Resets the decoder so that a new stream of Ogg Opus data 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 Ogg Opus data.

Properly using the Web Worker interface

OggOpusDecoderWebWorker 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 OggOpusDecoderWebWorker 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 }) => {
      // does something to play the audio data.
    }
    
    decoder.decodeFrame(data1).then(playAudio);
    decoder.decodeFrame(data2).then(playAudio);
    decoder.decodeFrame(data3).then(playAudio);
    
    // do some other operations while the audio is decoded
  • 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(data1); // blocks the main thread
    playAudio(decoded1);
    
    const decoded2 = await decoder.decodeFrame(data2); // blocks the main thread
    playAudio(decoded2);
    
    const decoded3 = await decoder.decodeFrame(data3); // blocks the main thread
    playAudio(decoded3);