Decode Opus audio streams immediately in chunks
npm install @drippy-music/opus-stream-decoderOpusStreamDecoder is an Emscripten JavaScript WebAssembly (Wasm) library for immediately decoding Ogg Opus audio streams (URLs or files) in chunks without waiting for the complete file to download, copy, or read. libopusfile is the underlying C library used for decoding. OpusStreamDecoder provides a lightweight JavaScript API for decoding Opus audio streams at near-native speeds.
_Note: This repository was forked from AnthumChris/fetch-stream-audio to decouple OpusStreamDecoder as a standalone Wasm decoder. It will be integrated back into demo as a git submodule for fetch-stream-audio #4._
Pre-compiled binaries and full examples are included in the dist/ folder. The OpusStreamDecoder API was designed to be simple and the pseudocode below explains its complete usage:
If using a front-end build system, you can obtain OpusStreamDecoder via require or import syntaxes:
``js`
const { OpusStreamDecoder } = require('opus-stream-decoder');
import { OpusStreamDecoder } from 'opus-stream-decoder';
Otherwise, include the script before you instantiate OpusStreamDecoder.
`javascript`
After instantiating OpusStreamDecoder, decode() should be called repeatedly until you're done reading the stream. You __must__ start decoding from the beginning of the file. Otherwise, a valid Ogg Opus file will not be discovered by libopusfile for decoding. decoder.ready is a Promise that resolves once the underlying WebAssembly module is fetched from the network and instantiated, so ensure you always wait for it to resolve. free() should be called when done decoding, when decode() throws an error, or if you wish to "reset" the decoder and begin decoding a new file with the same instance. free() releases the allocated Wasm memory.
#### Performance
To achieve optimum decoding performance, OpusStreamDecoder should ideally be run in a Web Worker to keep CPU decoding computations on a sepearate browser thread. (_TODO: provide web worker example._)
Additionally, onDecode will be called thousands of times while decoding Opus files. Keep your onDecode callbacks lean. The multiple calls result intentionally because of Opus' unmatched low-latency decoding advantage (read more)—audio is decoded as soon as possible . For example, a 60-second Opus file encoded with a 20ms frame/packet size would yield 3,000 onDecode calls (60 * 1000 / 20), because the underlying libopusfile C decoding function op_read_float_stereo() currently decodes one frame at a time during my tests.
The dist/ folder will contain all required files, tests, and examples after building.
$ git submodule update --init
`_TODO: consider moving this to Makefile_
$3
Emscripten is used to compile the C libraries to be compatible with WebAssembly. This repo was tested with 1.39.5.
* Emscripten Installation Instructions
$3
`
$ make clean dist
`The Emscripten module builds in a few seconds, but most of the work will be spent configuring the dependencies
libopus, libogg, and libopusfile. You may see the warnings (not errors) below, which don't prevent the build from succeeding. It is not known whether these warnings adversly affect runtime use.- Don't have the functions lrint() and lrintf ()
- Replacing these functions with a standard C cast
- implicit conversion from 'unsigned int' to 'float'
$3
#### Error: "autoreconf: command not found"
$ brew install automake#### "./autogen.sh: No such file or directory"
$ brew install autogenTests & Examples
Two tests exist that will decode an Ogg Opus File with
OpusStreamDecoder. Both tests output "decoded _N_ samples." on success.$3
This test writes two decoded left/right PCM audio data to files in
tmp/. Install NodeJS and run:
`
$ make test-wasm-module
`$3
This test uses
fetch() to decode a URL file stream in chunks. Serve the dist/ folder from a web server and open test-opus-stream-decoder.html in the browser. HTTP/HTTPS schemes are required for Wasm to load—opening it directly with file:// probably won't work.You can also run
SimpleHTTPServer and navigate to http://localhost:8000/test-opus-stream-decoder.html
`
$ cd dist
$ python -m SimpleHTTPServer 8000
`Developing
$3
See files
src/*.{js,html} and use $ make and $ make clean to build into dist/$3
See C files
src/opus_chunkdecoder* and use $ make native-decode-test, which allows you to compile and test almost instantly. native-decode-test is a fast workflow that ensures things work properly independently of Emscripten and Wasm before you integrate it.You'll need to install
libopusfile binaries natively on your system (on Mac use $ brew install opusfile). Then, declare environment variables with the locations of the installed libopusfile dependencies required by native-decode-test before running:
`
$ export OPUS_DIR=/usr/local/Cellar/opus/1.2.1
$ export OPUSFILE_DIR=/usr/local/Cellar/opusfile/0.10
$ make native-decode-test
``Note: If you see error "fatal error: 'stdarg.h' file not found", try running from a new terminal window that does not have Emscripten initialized.