New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

speaker

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

speaker - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

examples/sine.js

11

History.md

@@ -0,1 +1,12 @@

0.0.3 / 2012-11-03
==================
- a two examples to the "examples" dir
- emit an "open" event
- emit a "close" event
- emit a "flush" event
- properly support the "pipe" event
- mpg123: fix a CoreAudio backend compilation warning
- add a timeout after the flush call to ensure the backend has time to play
0.0.2 / 2012-10-25

@@ -2,0 +13,0 @@ ==================

153

index.js

@@ -40,14 +40,5 @@

// set default options
if (!opts) opts = {};
if (null == opts.channels) opts.channels = 2;
if (null == opts.bitDepth) opts.bitDepth = 16;
if (null == opts.sampleRate) opts.sampleRate = 44100;
if (null == opts.signed) opts.signed = opts.bitDepth != 8;
// set options if provided
if (opts) this._opts(opts);
// initialize the audio handle
// TODO: open async?
this.audio_handle = new Buffer(binding.sizeof_audio_output_t);
binding.open(this.audio_handle, opts);
// chunks are sent over to the backend in "samplesPerFrame * blockAlign" size.

@@ -57,16 +48,10 @@ // this is necessary because if we send too big of chunks at once, then there

// CoreAudio backend)
if (null == opts.samplesPerFrame) opts.samplesPerFrame = 1024;
this.samplesPerFrame = 1024;
// copy over options
this.signed = opts.signed;
this.channels = opts.channels;
this.bitDepth = opts.bitDepth;
this.sampleRate = opts.sampleRate;
this.samplesPerFrame = opts.samplesPerFrame;
// flipped after close() is called, no write() calls allowed after
this._closed = false;
// calculate the "block align"
this.blockAlign = this.bitDepth / 8 * this.channels;
// call `flush()` upon the "finish" event
this.on('finish', this._flush);
this.on('pipe', this._pipe);
}

@@ -76,2 +61,72 @@ inherits(Speaker, Writable);

/**
* Calls the audio backend's `open()` function, and then emits an "open" event.
*/
Speaker.prototype._open = function () {
debug('open()');
if (this.audio_handle) {
throw new Error('_open() called more than once!');
}
// set default options, if not set
if (null == this.channels) {
debug('setting default "channels"', 2);
this.channels = 2;
}
if (null == this.bitDepth) {
debug('setting default "bitDepth"', 16);
this.bitDepth = 16;
}
if (null == this.sampleRate) {
debug('setting default "sampleRate"', 44100);
this.sampleRate = 44100;
}
if (null == this.signed) {
debug('setting default "signed"', this.bitDepth != 8);
this.signed = this.bitDepth != 8;
}
// calculate the "block align"
this.blockAlign = this.bitDepth / 8 * this.channels;
// initialize the audio handle
// TODO: open async?
this.audio_handle = new Buffer(binding.sizeof_audio_output_t);
var r = binding.open(this.audio_handle, this);
if (0 !== r) {
throw new Error('open() failed: ' + r);
}
this.emit('open');
return this.audio_handle;
};
/**
* set given options
*/
Speaker.prototype._opts = function (opts) {
debug('opts(%j)', opts);
if (null != opts.channels) {
debug('setting "channels"', opts.channels);
this.channels = opts.channels;
}
if (null != opts.bitDepth) {
debug('setting "bitDepth"', opts.bitDepth);
this.bitDepth = opts.bitDepth;
}
if (null != opts.sampleRate) {
debug('setting "sampleRate"', opts.sampleRate);
this.sampleRate = opts.sampleRate;
}
if (null != opts.signed) {
debug('setting "signed"', opts.signed);
this.signed = opts.signed;
}
if (null != opts.samplesPerFrame) {
debug('setting "samplesPerFrame"', opts.samplesPerFrame);
this.samplesPerFrame = opts.samplesPerFrame;
}
};
/**
* `_write()` callback for the Writable base class.

@@ -82,5 +137,13 @@ */

debug('_write() (%d bytes)', chunk.length);
if (this._closed) {
// close() has already been called. this should not be called
return done(new Error('write() call after close() call'));
}
var b;
var left = chunk;
var handle = this.audio_handle;
if (!handle) {
// this is the first time write() is being called; need to _open()
handle = this._open();
}
var chunkSize = this.blockAlign * this.samplesPerFrame;

@@ -115,11 +178,49 @@

/**
* Calls the `flush()` and `close()` bindings for the audio backend.
* Called when this stream is pipe()d to from another readable stream.
* If the "sampleRate", "channels", "bitDepth", and "signed" properties are,
* set, then they will be used over the currently set values.
*/
Speaker.prototype._pipe = function (source) {
debug('_pipe()');
this._opts(source);
};
/**
* Calls the `flush()` bindings for the audio backend.
*/
Speaker.prototype._flush = function () {
debug('_flush()');
var handle = this.audio_handle;
// TODO: async
binding.flush(handle);
binding.close(handle);
// TODO: async definitely
binding.flush(this.audio_handle);
this.emit('flush');
// XXX: The audio backends keep ~.5 seconds worth of buffered audio data
// in their system, so presumably there will be .5 seconds *more* of audio data
// coming out the speakers, so we must keep the event loop alive so the process
// doesn't exit. This is a nasty, nasty hack and hopefully there's a better way
// to be notified when the audio has acutally finished playing.
setTimeout(this.close.bind(this), 600);
};
/**
* Closes the audio backend. Normally this function will be called automatically
* after the audio backend has finished playing the audio buffer through the
* speakers.
*
* @api public
*/
Speaker.prototype.close = function () {
debug('close()');
// TODO: async maybe?
binding.close(this.audio_handle);
this.emit('close');
this.audio_handle = null;
this._closed = true;
};

2

package.json

@@ -20,3 +20,3 @@ {

],
"version": "0.0.2",
"version": "0.0.3",
"author": "Nathan Rajlich <nathan@tootallnate.net> (http://tootallnate.net)",

@@ -23,0 +23,0 @@ "repository": {

@@ -44,7 +44,33 @@ node-speaker

### Speaker class
`require('speaker')` directly returns the `Speaker` constructor. It is the only
interface exported by node-speaker.
TODO: document...
### new Speaker([ format ]) -> Speaker instance;
Creates a new `Speaker` instance, which is a writable stream that you can pipe raw
PCM audio data to. The optional `format` object may contain any of the `Writable`
base class options, as well as any of these PCM formatting options:
* `channels` - The number of audio channels. PCM data must be interleaved. Defaults to `2`.
* `bitDepth` - The number of bits per sample. Defaults to `16` (16-bit).
* `sampleRate` - The number of samples per second per channel. Defaults to `44100`.
* `signed` - Boolean specifying if the samples are signed or unsigned. Defaults to `true` when bit depth is 8-bit, `false` otherwise.
* `samplesPerFrame` The number of samples to send to the audio backend at a time. You likely don't need to mess with this value. Defaults to `1024`.
#### "open" event
Fired when the backend `open()` call has completed. This happens once the first
`write()` call happens on the speaker instance.
#### "flush" event
Fired after the speaker instance has had `end()` called, and after the audio data
has been flushed to the speakers.
#### "close" event
Fired after the "flush" event, after the backend `close()` call has completed.
This speaker instance is essentially finished after this point.
Audio Backend Selection

@@ -51,0 +77,0 @@ -----------------------

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc