@alexanderolsen/silence-listener-node
Version:
Pseudo-AudioNode to notify when an audio stream becomes silent.
211 lines (164 loc) • 7.7 kB
Markdown
# silence-listener-node
 [](https://coveralls.io/github/aolsenjazz/silence-listener-node?branch=main) [](https://codeclimate.com/github/aolsenjazz/silence-listener-node/maintainability) 
SilenceListenerNode is a [pseudo](https://github.com/WebAudio/web-audio-api/issues/251)-[AudioNode](https://developer.mozilla.org/en-US/docs/Web/API/AudioNode) which invokes a callback function whenever a stream of audio becomes or unbecomes silent. Uses [AudioWorklet](https://developers.google.com/web/updates/2017/12/audio-worklet) when available, falling back to [ScriptProcessorNode](https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode) when Worklets are not available.
## Installation
Install using NPM:
```bash
npm i /silence-listener-node
```
## Setup
To utilize AudioWorklet functionality, you **must** copy the `sln.worklet.js` file in */node_modules/@alexanderolsen/silence-listener-node/dist/* to where the library can find it. The default location for this file is at the server root (*/sln.worklet.js*). This location can be changed using the options dict passed into `createSilenceListenerNode()`:
```javascript
createSilenceListenerNode(context, nChannels, {
pathToWorklet: '/some/path/to/sln.worklet.js', // default '/sln.worklet.js'
});
```
See **Configuration** for more instructions on using the `options` dict.
## Usage
### In modules:
```javascript
import { createSilenceListenerNode } from '/silence-listener-node';
let context = new AudioContext();
let nChannels = 2;
let options = {}; // see **Configuration**
let buffSource = context.createBufferSource();
createSilenceListenerNode(context, nChannels, options)
.then((silenceListenerNode) => {
buffSource.connect(silenceListenerNode);
silenceListenerNode.connect(context.destination);
buffSource.start();
});
```
or
```javascript
const createSilenceListenerNode = require('/silence-listener-node').createSilenceListenerNode;
(async function() {
let context = new AudioContext();
let nChannels = 2;
let options = {}; // see **Configuration**
let buffSource = context.createBufferSource();
let silenceListenerNode = await createSilenceListenerNode(context, nChannels, options);
buffSource.connect(silenceListenerNode);
silenceListenerNode.connect(context.destination);
buffSource.start();
})();
```
### In HTML:
```html
<script src="https://cdn.jsdelivr.net/npm/@alexanderolsen/silence-listener-node"></script>
<script>
var context = new AudioContext();
var nChannels = 2;
var options = {}; // see **Configuration**
let buffSource = context.createBufferSource();
SilenceListenerNode.createSilenceListenerNode(context, nChannels, options)
.then((silenceListenerNode) => {
buffSource.connect(silenceListenerNode);
silenceListenerNode.connect(context.destination);
buffSource.start();
});
</script>
```
Or use the silence-listener-node.js file in the *dist* folder:
```html
<script src="silence-listener-node.js"></script>
```
## Configuration
When creating a SilenceListenerNode instance, you have number of options available:
```javascript
let context = new AudioContext();
let nChannels = 2;
// entries are defaults
let options = {
nInputs: 1, // The number of inputs connected to this node. Probably 1
nOutputs: 1, // The number of outputs connected to this node. Probably 1
batchSize: 512, // Stuck at 128 for `AudioWorklet`s. Can be powers of 2 where 256 < batchSize < 16384
silenceThreshold: Math.floor(44100 / batchSize), // This is the number of silent batches which must
// occur before silence callbacks are invoked.
pathToWorklet: '/sln.worklet.js' //The path to the worklet file
}
createSilenceListenerNode(context, nChannels, options).then((silenceListenerNode) => { ... });
```
#### `nInputs`
The number of `AudioNode`s connected to this instance of SilenceListenerNode. Default 1.
#### `nOutputs`
The nubmer of outputs `AudioNode`s this instance of SilenceLisnerNode is connected to. Default 1.
#### `batchSize`
Modifies the batch size processed by `ScriptProcessorNode`. This does not affect `AudioWorklet`s as they're stuck at 128. If using ScriptProcessorNode, must be one of the following: `[256, 512, 1024, 2048, 4096, 8192, 16384]`.
#### `silenceThreshold`
The number of silent batches which must occur before the audio stream will be flagged as silent. Default is (roughly) one second worth of audio.
#### `pathToWorklet`
The location of your *sln.worklet.js* file. Default is at server root.
## API Reference
Once you've created the SilenceListenerNode using `createSilenceListener()` or `SilenceListenerNode.createSilenceListener()`, the returned object exposes:
### `connect`
```javascript
/**
* Connects SilenceListenerNode to the specific destination AudioNode
*
* @param {AudioNode} destination The node to connect to
*/
connect(destination) { ... }
```
### `disconnect`
```javascript
/** Disconnects from the currently-connected AudioNode */
disconnect() { ... }
```
### `subscribeToSilence`
```javascript
/**
* Begin receiving silence notifications
*
* @param { Function(isSilent, timeSinceLast) } callback Invoked whenever audio becomes or unbecomes silent
* @return { String } id of the subscription. use with unsubscribeFromSilence(id) to stop receiving notifications
*/
subscribeToSilence(callback) { ... }
```
### `unsubscribeFromSilence`
```javascript
/**
* Stop receiving silence events for given ID.
*
* @param { String } id Identifier for callback subscription
*/
unsubscribeFromSilence(id) { ... }
```
### `getters`
```javascript
get silent() { ... }
get silence() { ... } // for simplicity
get numberOfInputs() { ... }
get numberOfOutputs() { ... }
get channelCount() { ... }
get channelCountMode() { ... }
get channelInterpretation() { ... }
// e.g. let isSilent = silenceListenerNode.silent;
```
### `setters`
```javascript
set channelCount(channelCount) { ... }
set channelCountMode(channelCountMode) { ... }
set channelInterpretation(channelInterpretation) { ... }
// e.g. silenceListenerNode.channelInterpretation = 'speakers';
```
## Examples
Run any server ([http-server](https://www.npmjs.com/package/http-server), etc) from the project directory:
```bash
cd silence-listener-node
http-server
```
and visit *localhost:8080/examples/basic* or *localhost:8080/examples/react* in a browser. Examples **must be** hosted from the root directory, as they need to access the files in *dist*.
## Building From Source
```bash
git clone https://github.com/aolsenjazz/silence-listener-node
cd silence-listener-node
npm run watch
```
Production files are placed in the *dist* directory.
## Uncaught (in promise) DOMException: The user aborted a request.
This super unhelpful error message occurs when SilenceListenerNode is unable to find your sln.worklet.js. To fix this, make sure your `options.pathToWorklet` is set correctly and that the file is actually reachable at that location.
## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
## License
Licenses are available in `LICENSE.md`.