audio-vs1053b
Advanced tools
Comparing version 0.1.91 to 0.2.0
@@ -14,3 +14,3 @@ // Any copyright is dedicated to the Public Domain. | ||
audio.on('ready', function () { // Start recording data for a second into a file | ||
audio.setOutput('headphone', function(err) { | ||
audio.setOutput('headphones', function(err) { | ||
// Open a file | ||
@@ -17,0 +17,0 @@ var audioFile = fs.readFileSync('sample.mp3'); |
@@ -18,4 +18,4 @@ // Any copyright is dedicated to the Public Domain. | ||
console.log("Audio module connected! Setting volume..."); | ||
// Set the volume in decibels. Around 20 is good; smaller is louder. | ||
audio.setVolume(20, function(err) { | ||
// Set the volume in decibels. Around .8 is good; 80% max volume or -25db | ||
audio.setVolume(.8, function(err) { | ||
if (err) { | ||
@@ -22,0 +22,0 @@ return console.log(err); |
@@ -15,3 +15,3 @@ // Any copyright is dedicated to the Public Domain. | ||
// Start recording data for a second into a file | ||
audio.setOutput('headphone', function(err) { | ||
audio.setOutput('headphones', function(err) { | ||
// Open a file | ||
@@ -18,0 +18,0 @@ fs.createReadStream('sample.mp3').pipe(audio.createPlayStream()); |
968
index.js
@@ -16,2 +16,3 @@ // Copyright 2014 Technical Machine, Inc. See the COPYRIGHT | ||
var Readable = require('stream').Readable; | ||
var queue = require('sync-queue'); | ||
@@ -36,4 +37,6 @@ // VS10xx SCI Registers | ||
// VS10xx Reset Command | ||
var MODE_SM_RESET = 0x04; | ||
// VS10xx GPIO Register adddresses | ||
var GPIO_DIR_ADDR = 0xC017 | ||
@@ -43,17 +46,40 @@ , GPIO_READ_ADDR = 0xC018 | ||
// VS10xx GPIO for i/o | ||
var inputReg = 0x05, | ||
outputReg = 0x07; | ||
// Datastructure for storing pending buffers and their allbacks | ||
var _audioCallbacks = {}; | ||
// A double buffer for recording data | ||
var _fillBuff = new Buffer(25000); | ||
_fillBuff.fill(0); | ||
function use (hardware, next) { | ||
return new Audio(hardware, next); | ||
// The SPI bus clock speed | ||
var SPIClockSpeed = 4000000; | ||
/* | ||
* Both use() and Audio() initialize the audio module with a specific piece of hardware. | ||
* use() is a common API wrapper around object construction for Tessel modules. Arguments: | ||
* | ||
* hardware The hardware the module is connected to (Tessel Port) | ||
* | ||
* callback A callback to be called when initialization completes. Upon | ||
* success, callback is invoked as callback(null, audio), | ||
* where `audio` is an Audio module object. Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for several reasons: | ||
* | ||
* Error Created when Tessel cannot communicate with the module or | ||
* it receives a response that doesn't match with what was expected. | ||
* | ||
*/ | ||
function use (hardware, callback) { | ||
return new Audio(hardware, callback); | ||
} | ||
function Audio(hardware, callback) { | ||
var self = this; | ||
// Set the spi port | ||
this.spi = new hardware.SPI({ | ||
self.spi = new hardware.SPI({ | ||
clockSpeed: 1000000, | ||
@@ -63,21 +89,25 @@ dataMode: 0 | ||
// Create a new queue to store commands | ||
self.commandQueue = new queue(); | ||
// Set our register select pins | ||
this.MP3_XCS = hardware.digital[0].output(true); //Control Chip Select Pin (for accessing SPI Control/Status registers) | ||
this.MP3_DCS = hardware.digital[1].output(true); //Data Chip Select / BSYNC Pin | ||
this.MP3_DREQ = hardware.digital[2].input() //Data Request Pin: Player asks for more data | ||
self.MP3_XCS = hardware.digital[0].output(true); //Control Chip Select Pin (for accessing SPI Control/Status registers) | ||
self.MP3_DCS = hardware.digital[1].output(true); //Data Chip Select / BSYNC Pin | ||
self.MP3_DREQ = hardware.digital[2].input() //Data Request Pin: Player asks for more data | ||
this.input = ""; | ||
this.output = ""; | ||
// Initializing state variables | ||
self.input; | ||
self.output; | ||
// Waits for the audio completion event which signifies that a buffer has finished streaming | ||
process.on('audio_playback_complete', this._handlePlaybackComplete.bind(this)); | ||
process.on('audio_playback_complete', self._handlePlaybackComplete.bind(self)); | ||
// Waits for the audio data event which is recorded data being output from the C shim | ||
process.on('audio_recording_data', this._handleRecordedData.bind(this)); | ||
process.on('audio_recording_data', self._handleRecordedData.bind(self)); | ||
// Waits for final flushed buffer of a recording | ||
process.on('audio_recording_complete', this._handleRecordedData.bind(this)); | ||
process.on('audio_recording_complete', self._handleRecordedData.bind(self)); | ||
// Initialize the module | ||
this.initialize(callback); | ||
self.commandQueue.place(self.initialize.bind(self, callback)); | ||
} | ||
@@ -87,2 +117,16 @@ | ||
/* | ||
* Reset the Audio module and set it into a known, default state | ||
* | ||
* callback A callback to be called when initialization completes. Upon | ||
* success, callback is invoked as callback(null, audio), | ||
* where `audio` is an Audio module object. Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for several reasons: | ||
* | ||
* Error Created when Tessel cannot communicate with the module or | ||
* it receives a response that doesn't match with what was expected. | ||
* | ||
*/ | ||
Audio.prototype.initialize = function(callback) { | ||
@@ -93,16 +137,12 @@ var self = this; | ||
this._softReset(function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
if (!self._failConnect(err, callback)) { | ||
// Make sure we can comm and have the right version | ||
self._checkVersion(function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
if (!self._failConnect(err, callback)) { | ||
// Set the clock speed higher | ||
self._setClockSpeeds(function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
if (!self._failConnect(err, callback)) { | ||
// Enabke headphones and lineIn | ||
self.setDefaultIO(function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
if (!self._failConnect(err, callback)) { | ||
// Call the callback | ||
@@ -116,2 +156,4 @@ callback && callback(null, self); | ||
}); | ||
self.commandQueue.next(); | ||
} | ||
@@ -125,6 +167,39 @@ }); | ||
/* | ||
* (Internal Function) The callback for the event when a stream finishes playing. | ||
* This method is responsible for calling any callbacks associated with a given stream's | ||
* completion and releasing the SPI lock if there are no more active streams. | ||
* | ||
* errBool An indicator of whether there was an error with playback. | ||
* | ||
* completedStream The track id of the buffer that just completed. This is the key | ||
* stored in the callbacks datastructure for fetching the track information. | ||
* | ||
*/ | ||
Audio.prototype._handlePlaybackComplete = function(errBool, completedStream) { | ||
var self = this; | ||
if (self.lock) { | ||
// Get the callback if one was saved | ||
var track = _audioCallbacks[completedStream]; | ||
// If it exists | ||
if (track) { | ||
// Remove it from our datastructure | ||
delete _audioCallbacks[completedStream]; | ||
// Call the callback | ||
if (track.callback) { | ||
track.callback(); | ||
} | ||
// Emit the end event | ||
self.emit('end', err); | ||
} | ||
// Get the number of streams still playing | ||
var remaining = Object.keys(_audioCallbacks).length; | ||
// If there are not still tracks playing and we have a lock reference | ||
if (!remaining && self.lock) { | ||
// Free the lock | ||
self.lock.release(function(err) { | ||
@@ -135,22 +210,2 @@ if (err) { | ||
} | ||
else { | ||
// Get the callback if one was saved | ||
var callback = _audioCallbacks[completedStream]; | ||
// If it exists | ||
if (callback) { | ||
// Remove it from our datastructure | ||
delete _audioCallbacks[completedStream]; | ||
var err; | ||
// Generate an error message if there was an error | ||
if (errBool) { | ||
err = new Error("Error sending buffer over SPI"); | ||
} | ||
// Call the callback | ||
callback(err); | ||
self.emit('end', err); | ||
} | ||
} | ||
}); | ||
@@ -160,2 +215,10 @@ } | ||
/* | ||
* (Internal Function) The callback for when a buffer of recorded data is returned from the C shim. | ||
* This function is called repeatedly as a recording is made. | ||
* | ||
* length The number of bytes that that were recorded. | ||
* | ||
*/ | ||
Audio.prototype._handleRecordedData = function(length) { | ||
@@ -168,10 +231,38 @@ // Copy the recorded data into a new buff for consumption | ||
/* | ||
* (Internal Function) A helper function to simplify error handling. It checks if an error occured, | ||
* calls a callback if one was provided, or emits an error event. | ||
* | ||
* hardware The hardware the module is connected to (Tessel Port) | ||
* | ||
* callback A callback to be called when initialization completes. | ||
* | ||
* This function returns a boolean that indicates whether an error was handled (value of true). | ||
*/ | ||
Audio.prototype._failConnect = function(err, callback) { | ||
setImmediate(function() { | ||
this.emit('error', err); | ||
}.bind(this)) | ||
return callback && callback(err); | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
else { | ||
setImmediate(function() { | ||
this.emit('error', err); | ||
}.bind(this)) | ||
} | ||
return true | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
/* | ||
* Opens up a writable stream which gets piped to the C shim for playback. Internally, | ||
* it calls the queue method repeatedly. It continues concatenating piped data until | ||
* the buffer is equal or greater than 10k bytes to ensure smooth playback. | ||
*/ | ||
Audio.prototype.createPlayStream = function() { | ||
@@ -228,3 +319,10 @@ var audio = this; | ||
// Creates a Readable record stream | ||
/* | ||
* Opens up a readable stream where recording data will be emitted on an interval. Arguments: | ||
* | ||
* profile A string that indicates with recording profile will be used. | ||
* The recording profile determines the sound quality. Available sound | ||
* qualities can be found by calling availableRecordingProfiles() | ||
*/ | ||
Audio.prototype.createRecordStream = function(profile) { | ||
@@ -254,3 +352,13 @@ var audio = this; | ||
/* | ||
* (Internal Function) Performs a soft reset of the Audio module. Arguments: | ||
* | ||
* callback A callback to be called when resetting completes. Upon | ||
* success, callback is invoked as callback(null). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._softReset = function(callback) { | ||
@@ -271,2 +379,16 @@ this._readSciRegister16(SCI_MODE, function(err, mode) { | ||
/* | ||
* (Internal Function) Requests the chip version from the Audio Module to | ||
* confirm working communication and valid module. Arguments: | ||
* | ||
* callback A callback to be called when checking completes. Upon | ||
* success, callback is invoked as callback(null). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. It | ||
* can also fail if the returned version is not what was expected. | ||
*/ | ||
Audio.prototype._checkVersion = function(callback) { | ||
@@ -286,2 +408,13 @@ this._readSciRegister16(SCI_STATUS, function(err, MP3Status) { | ||
/* | ||
* (Internal Function) Sets the VS1053B clock speed. Arguments: | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(null). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._setClockSpeeds = function(callback) { | ||
@@ -292,3 +425,3 @@ // Set multiplier to 3.0x | ||
else { | ||
this.spi.setClockSpeed(4000000); | ||
this.spi.setClockSpeed(SPIClockSpeed); | ||
return callback && callback(); | ||
@@ -300,2 +433,15 @@ } | ||
/* | ||
* (Internal Function) Transfer a single byte over SPI to the VS1053b. Arguments: | ||
* | ||
* byte The byte value to be transferred. | ||
* | ||
* callback A callback to be called when sending completes. Upon | ||
* success, callback is invoked as callback(null). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._SPItransferByte = function(byte, callback) { | ||
@@ -307,2 +453,16 @@ this._SPItransferArray([byte], function(err, ret) { | ||
/* | ||
* (Internal Function) Transfer an array of bytes over SPI to the vs1053b | ||
* Arguments: | ||
* | ||
* array An array of bytes to be sent over spi | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(null). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._SPItransferArray = function(array, callback) { | ||
@@ -314,3 +474,17 @@ this.spi.transfer(new Buffer(array), function(err, ret) { | ||
//Read the 16-bit value of a VS10xx register | ||
/* | ||
* (Internal Function) Read the 16-bit value of a VS10xx register | ||
* Arguments: | ||
* | ||
* addressbyte The address of the register to read | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(data) where data | ||
* is a 16-bit word. Upon failure, callback is invoked as | ||
* callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._readSciRegister16 = function(addressbyte, callback) { | ||
@@ -343,2 +517,20 @@ | ||
/* | ||
* (Internal Function) Write two 8-bit values value to a VS10xx register | ||
* Arguments: | ||
* | ||
* addressbyte The address of the register to write to | ||
* | ||
* highbyte The high 8-bit value to write | ||
* | ||
* lowbyte The low 8-bit value to write | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._writeSciRegister = function(addressbyte, highbyte, lowbyte, callback) { | ||
@@ -363,2 +555,18 @@ | ||
/* | ||
* (Internal Function) Write a 16-bit value to a VS10xx register | ||
* Arguments: | ||
* | ||
* addressbyte The address of the register to write to | ||
* | ||
* word The 16-bit word to write to the register | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._writeSciRegister16 = function(addressbyte, word, callback) { | ||
@@ -368,2 +576,17 @@ this._writeSciRegister(addressbyte, (word >> 8) & 0xFF, word & 0xFF, callback); | ||
/* | ||
* (Internal Function) Sets the direction of the VS1053b GPIOs. Arguments: | ||
* | ||
* arg The value of the direction register that will be written. | ||
* GPIOs to be used as outputs should have a 1 in the x bit | ||
* position where x is the GPIO number. | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._setChipGpioDir = function(arg, callback) { | ||
@@ -378,2 +601,17 @@ this._writeSciRegister16(SCI_WRAMADDR, GPIO_DIR_ADDR, function(err) { | ||
/* | ||
* (Internal Function) Sets the state of the VS1053b GPIO pins. Arguments: | ||
* | ||
* arg The value of the state register that will be written. | ||
* GPIOs to be set high should have a 1 in the x bit | ||
* position where x is the GPIO number. | ||
* | ||
* callback A callback to be called when setting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._setChipGpio = function(arg, callback) { | ||
@@ -385,2 +623,15 @@ this._writeSciRegister16(SCI_WRAMADDR, GPIO_SET_ADDR, function(err) { | ||
/* | ||
* (Internal Function) Get the direction of each of the VS1053b GPIO pins. Arguments: | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(state) where | ||
* state is a 16-bit word. The state can be interpreted | ||
* as GPIO outputs having a 1 in their bit position. Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._getChipGpioDir = function(callback) { | ||
@@ -390,2 +641,15 @@ this._getChipGPIOValue(GPIO_DIR_ADDR, callback); | ||
/* | ||
* (Internal Function) Get the state of each of the VS1053b GPIO pins. Arguments: | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(state) where | ||
* state is a 16-bit word. The state can be interpreted | ||
* as high GPIOs having a 1 in their bit position. Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._getChipGpio = function(callback) { | ||
@@ -395,2 +659,17 @@ this._getChipGPIOValueFromAddr(GPIO_READ_ADDR, callback); | ||
/* | ||
* (Internal Function) A helper function that fetches the value of a GPIO address. Arguments: | ||
* | ||
* gpioValue The Address of the GPIO bank to read | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(state) where | ||
* state is a 16-bit word. The state can be interpreted | ||
* as high GPIOs having a 1 in their bit position. Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._getChipGPIOValueFromAddr = function(gpioValue, callback) { | ||
@@ -410,2 +689,17 @@ this._writeSciRegister16(SCI_WRAMADDR, gpioValue, function(err) { | ||
/* | ||
* (Internal Function) In order to switch between different Audio inputs and outputs | ||
* GPIOs on board the VS1053b are used. GPIO 5 toggles between different inputs | ||
* and GPIO 7 toggles between different outputs. This function sets them both as | ||
* outputs which is required for setting them high or low (thus, toggling state). | ||
* Arguments: | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype._enableAudioOutput = function(callback) { | ||
@@ -415,89 +709,175 @@ this._setChipGpioDir((1 << 7) + (1 << 5), callback); | ||
/* | ||
* Sets the default input/output arrangements for the module. Arguments: | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype.setDefaultIO = function(callback) { | ||
var self = this; | ||
self._enableAudioOutput(function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
self.setInput('mic', function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
self.setOutput('headphones', function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
else { | ||
callback && callback(); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
self.commandQueue.place(function() { | ||
self._enableAudioOutput(function(err) { | ||
if (!self._failConnect(err, callback)) { | ||
self.setInput('mic', function(err) { | ||
if (!self._failConnect(err, callback)) { | ||
self.setOutput('headphones', function(err) { | ||
if (!self._failConnect(err, callback)) { | ||
callback && callback(); | ||
} | ||
}); | ||
} | ||
}); | ||
self.commandQueue.next(); | ||
} | ||
}); | ||
}); | ||
} | ||
Audio.prototype.setVolume = function(leftChannelDecibels, rightChannelDecibels, callback) { | ||
// If no volume was provided | ||
if (leftChannelDecibels === undefined) { | ||
// Just callback | ||
if (callback) { | ||
callback(); | ||
/* | ||
* Sets the output volume for the Module. Arguments: | ||
* | ||
* leftchannel A float that indicates the level of sound from the left audio. | ||
* channel. Can between 0 and 1, where 1 is the louded possible value. | ||
* | ||
* rightchannel [Optional] A float that indicates the level of sound from the left audio. | ||
* channel. Can between 0 and 1, where 1 is the louded possible value. | ||
* If this argument is omitted, the leftchannel value will be used. | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
*/ | ||
Audio.prototype.setVolume = function(leftChannel, rightChannel, callback) { | ||
var self = this; | ||
self.commandQueue.place(function() { | ||
if(typeof leftChannel !== 'number'){ // if no volume provided | ||
return (!typeof leftChannel === 'function') || leftChannel(); // call callback if provided | ||
} | ||
// and return | ||
return; | ||
} | ||
// If the user passed in one decibel level and a callback | ||
else if (typeof rightChannelDecibels === 'function' && !callback) { | ||
// set the callback | ||
callback = rightChannelDecibels; | ||
// And make both channels the same | ||
rightChannelDecibels = leftChannelDecibels; | ||
} | ||
// If the user only passed in a decibel level | ||
else if (rightChannelDecibels === undefined && callback === undefined) { | ||
// Make both channels the same | ||
rightChannelDecibels = leftChannelDecibels; | ||
} | ||
leftChannel = self._normalizeVolume(leftChannel); | ||
// The units are in half decibels | ||
leftChannelDecibels = leftChannelDecibels/0.5; | ||
rightChannelDecibels = rightChannelDecibels/0.5 | ||
// Set VS10xx Volume Register | ||
this._writeSciRegister(SCI_VOL, leftChannelDecibels, rightChannelDecibels, callback); | ||
if(typeof rightChannel !== 'number') { | ||
if(typeof rightChannel === 'function') { | ||
callback = rightChannel; | ||
} | ||
rightChannel = leftChannel; // set right channel = left channel | ||
} else { | ||
rightChannel = self._normalizeVolume(rightChannel); | ||
} | ||
// Set VS10xx Volume Register | ||
self._writeSciRegister(SCI_VOL, leftChannel, rightChannel, callback); | ||
setImmediate(self.commandQueue.next.bind(self)); | ||
}); | ||
} | ||
/* | ||
* (Internal Function) Converts user input from setVolume into a decibel level | ||
* that the VS1053b expects. Arguments: | ||
* | ||
* vol A float from 0-1 that indicates the level of sound. | ||
* | ||
*/ | ||
Audio.prototype._normalizeVolume = function(vol){ | ||
vol = (vol > 1) ? 1 : (vol < 0) ? 0 : vol; // make sure val is in the range 0-1. | ||
return Math.round((1 - vol) * 0xFE); // 0xFE = min sound level before completely off (0xFF) | ||
} | ||
/* | ||
* Toggles between line in and the oboard microphone as a recording input. Arguments: | ||
* | ||
* input A string that is either `mic` or `lineIn`. | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
* It may also be created if the provided input is invalid. | ||
*/ | ||
Audio.prototype.setInput = function(input, callback) { | ||
if (input != 'lineIn' && input != 'mic') { | ||
return callback && callback(new Error("Invalid input requested...")); | ||
} | ||
else { | ||
this.input = input; | ||
var self = this; | ||
this._getChipGpio(function(err, gpio) { | ||
if (err) { return callback && callback(err); } | ||
else { | ||
var newReg = (input === "lineIn" ? (gpio | (1 << inputReg)) : (gpio & ~(1 << inputReg))); | ||
this._setChipGpio(newReg, callback); | ||
} | ||
}.bind(this)); | ||
} | ||
self.commandQueue.place(function() { | ||
if (input != 'lineIn' && input != 'mic') { | ||
callback && callback(new Error("Invalid input requested...")); | ||
setImmediate(self.commandQueue.next.bind(self)); | ||
return | ||
} | ||
else { | ||
self.input = input; | ||
self._getChipGpio(function(err, gpio) { | ||
if (err) { return callback && callback(err); } | ||
else { | ||
var newReg = (input === "lineIn" ? (gpio | (1 << inputReg)) : (gpio & ~(1 << inputReg))); | ||
self._setChipGpio(newReg, callback); | ||
setImmediate(self.commandQueue.next.bind(self)); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
/* | ||
* Toggles between line out and headphones as the output signal. Arguments: | ||
* | ||
* output A string that is either `headphones` or `lineOut`. | ||
* | ||
* callback A callback to be called when getting completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for one primary reasons: | ||
* | ||
* Error Created when the SPI bus is unable or fails to transceive data. | ||
* It may also be created if the provided input is invalid. | ||
*/ | ||
Audio.prototype.setOutput = function(output, callback) { | ||
if (output != 'lineOut' && output != 'headphones') { | ||
return callback && callback(new Error("Invalid output requested...")); | ||
} | ||
else { | ||
this.output = output; | ||
this._getChipGpio(function(err, gpio) { | ||
if (err) { return callback && callback(err); } | ||
else { | ||
// Check if it's input or output and set the 7th bit of the gpio reg accordingly | ||
var newReg = (output === 'lineOut' ? (gpio | (1 << outputReg)) : (gpio & ~(1 << outputReg))); | ||
this._setChipGpio(newReg, callback); | ||
} | ||
}.bind(this)); | ||
} | ||
var self = this; | ||
self.commandQueue.place(function() { | ||
if (output != 'lineOut' && output != 'headphones') { | ||
callback && callback(new Error("Invalid output requested...")); | ||
setImmediate(self.commandQueue.next.bind(self)); | ||
return; | ||
} | ||
else { | ||
self.output = output; | ||
self._getChipGpio(function(err, gpio) { | ||
if (err) { return callback && callback(err); } | ||
else { | ||
// Check if it's input or output and set the 7th bit of the gpio reg accordingly | ||
var newReg = (output === 'lineOut' ? (gpio | (1 << outputReg)) : (gpio & ~(1 << outputReg))); | ||
self._setChipGpio(newReg, callback); | ||
setImmediate(self.commandQueue.next.bind(self)); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
/* | ||
* A helper class to keep track of the state of a provided buffer | ||
* | ||
* _buflen The length of a buffer | ||
* | ||
* id The generated ID that is used to distinguish the track from others | ||
* | ||
* callback A callback to be called when track playback completes | ||
*/ | ||
function Track(length, id, callback) { | ||
@@ -511,2 +891,20 @@ this._buflen = length; | ||
/* | ||
* Stops any currently playing tracks and places a new track at the beginning of the queue. | ||
* Playback will start immediately. Arguments: | ||
* | ||
* buff A sound Buffer in a format that is supported by the VS1053b | ||
* | ||
* callback A callback to be called when playback completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for a number of reasons: | ||
* | ||
* Error Could be returned if the Audio module can't obtain a lock | ||
* on the SPI bus. It could be returned if the module is currently | ||
* recording. It could be returned if all GPIO interrupts are | ||
* being used elsewhere. It could be returned if there is no more | ||
* available RAM memory for streaming. | ||
*/ | ||
Audio.prototype.play = function(buff, callback) { | ||
@@ -533,24 +931,50 @@ // Check if no buffer was passed in but a callback was | ||
self.spi.lock(function(err, lock) { | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
self.commandQueue.place(function() { | ||
return; | ||
// If we don't have a lock | ||
if (!self.lock) { | ||
// Obtain a lock | ||
self.spi.lock(function(err, lock) { | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
self.commandQueue.next(); | ||
return; | ||
} | ||
// Keep a reference to the lock | ||
self.lock = lock; | ||
// Play the track | ||
_play_helper(); | ||
}); | ||
} | ||
else { | ||
// Play the track | ||
_play_helper(); | ||
} | ||
// Save the lock reference so we can free it later | ||
self.lock = lock; | ||
// Send this buffer off to our shim to have it start playing | ||
var streamID = hw.audio_play_buffer(self.MP3_XCS.pin, self.MP3_DCS.pin, self.MP3_DREQ.pin, buff, buff.length); | ||
function _play_helper() { | ||
// Send this buffer off to our shim to have it start playing | ||
var streamID = hw.audio_play_buffer(self.MP3_XCS.pin, self.MP3_DCS.pin, self.MP3_DREQ.pin, buff, buff.length); | ||
var track = new Track(buff.length, streamID, callback); | ||
var track = new Track(buff.length, streamID, callback); | ||
self._handleTrack(track); | ||
self._handleTrack(track); | ||
self.emit('play', track); | ||
self.emit('play', track); | ||
self.commandQueue.next(); | ||
} | ||
}); | ||
} | ||
/* | ||
* (Internal Function) Checks the callback of the queue or play command for error and | ||
* places the created track onto the callbacks datastructure so their callback can | ||
* be called upon completion. Arguments: | ||
* | ||
* track A Track Object created with a sound buffer | ||
*/ | ||
Audio.prototype._handleTrack = function(track) { | ||
@@ -579,7 +1003,4 @@ // If stream id is less than zero, an error occured | ||
else { | ||
// If a callback was provided | ||
if (track.callback) { | ||
// Add it to the callbacks dict | ||
_audioCallbacks[track.id] = track.callback; | ||
} | ||
_audioCallbacks[track.id] = track; | ||
@@ -590,2 +1011,20 @@ this.emit('queued', track.id); | ||
/* | ||
* Places a sound buffer at the end of the queue. Any currently playing tracks will continue. | ||
* Arguments: | ||
* | ||
* buff A sound Buffer in a format that is supported by the VS1053b | ||
* | ||
* callback A callback to be called when queueing completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for a number of reasons: | ||
* | ||
* Error Could be returned if the Audio module can't obtain a lock | ||
* on the SPI bus. It could be returned if the module is currently | ||
* recording. It could be returned if all GPIO interrupts are | ||
* being used elsewhere. It could be returned if there is no more | ||
* available RAM memory for streaming. | ||
*/ | ||
Audio.prototype.queue = function(buff, callback) { | ||
@@ -608,25 +1047,35 @@ var self = this; | ||
// Initialize SPI to the correct settings | ||
self.spi.initialize(); | ||
self.commandQueue.place(function() { | ||
// If we don't have a SPI lock | ||
if (!self.lock) { | ||
// Initialize SPI to the correct settings | ||
self.spi._initialize(); | ||
// If there was a lock in place, wait until it's released, and we have it | ||
self.spi.lock(function(err, lock) { | ||
// If there was a lock in place, wait until it's released | ||
self.spi.lock(function(err, lock) { | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
self.commandQueue.next(); | ||
return; | ||
} | ||
else { | ||
self.lock = lock; | ||
// Release the lock so that we don't wait until complete for next queue | ||
lock.release(); | ||
self.lock = null; | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
// Queue the data | ||
_queue_helper(); | ||
} | ||
}); | ||
} | ||
else { | ||
// Queue the data | ||
_queue_helper(); | ||
} | ||
function _queue_helper() { | ||
var streamID = hw.audio_queue_buffer(self.MP3_XCS.pin, self.MP3_DCS.pin, self.MP3_DREQ.pin, buff, buff.length); | ||
var track = new Track(buf_len, streamID, callback); | ||
self._handleTrack(track); | ||
self.commandQueue.next(); | ||
} | ||
@@ -636,2 +1085,16 @@ }); | ||
/* | ||
* Pauses playback of the first sound buffer in the queue. Can be continued with resume(). | ||
* Arguments | ||
* | ||
* callback A callback to be called when pausing completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for a number of reasons: | ||
* | ||
* Error Could be returned if the Audio module can't obtain a lock | ||
* on the SPI bus. It could be returned if the module is currently | ||
* recording. | ||
*/ | ||
Audio.prototype.pause = function(callback) { | ||
@@ -648,21 +1111,38 @@ var err; | ||
// If we have a lock on the spi bus | ||
if (this.lock) { | ||
// Release it | ||
this.lock.release(function(err) { | ||
// Call the callback if we have one | ||
self.commandQueue.place(function() { | ||
// If we have a lock on the spi bus | ||
if (this.lock) { | ||
// Release it | ||
this.lock.release(function(err) { | ||
// Call the callback if we have one | ||
if (callback) { | ||
callback(err); | ||
} | ||
self.commandQueue.next(); | ||
return; | ||
}); | ||
} | ||
// If there is no lock, just call the callback | ||
else { | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
}); | ||
} | ||
// If there is no lock, just call the callback | ||
else { | ||
if (callback) { | ||
callback(err); | ||
self.commandQueue.next(); | ||
} | ||
} | ||
}); | ||
} | ||
/* | ||
* Stops the playback of an audio buffer and clears the queue. | ||
* | ||
* callback A callback to be called when stopping completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for a number of reasons: | ||
* | ||
* Error Could be returned if the Audio module can't obtain a lock | ||
* on the SPI bus. It could be returned if the module is currently | ||
* recording. | ||
*/ | ||
Audio.prototype.stop = function(callback) { | ||
@@ -677,20 +1157,29 @@ var err; | ||
// If we have a lock on the spi bus | ||
if (this.lock) { | ||
// Release it | ||
this.lock.release(function(err) { | ||
// Call the callback if we have one | ||
self.commandQueue.place(function() { | ||
if (this.lock) { | ||
// Release it | ||
this.lock.release(function(err) { | ||
// Call the callback if we have one | ||
if (callback) { | ||
callback(err); | ||
} | ||
self.commandQueue.next(); | ||
return; | ||
}); | ||
} | ||
// If there is no lock, just call the callback | ||
else { | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
}); | ||
} | ||
// If there is no lock, just call the callback | ||
else { | ||
if (callback) { | ||
callback(err); | ||
self.commandQueue.next(); | ||
} | ||
} | ||
}); | ||
} | ||
/* | ||
* Returns an array of the available recording profiles that can be provided to | ||
* startRecording(). | ||
* | ||
*/ | ||
Audio.prototype.availableRecordingProfiles = function() { | ||
@@ -706,4 +1195,20 @@ return [ | ||
/* | ||
* Start recording sound through the input. Data can be collected with the `data | ||
* event. | ||
* | ||
* profile The recording profile to use (sets the sound quality). By | ||
* default, the best voice recording profile is used. | ||
* | ||
* callback A callback to be called when recording starts. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for a number of reasons: | ||
* | ||
* Error Could be returned if memory for the incoming sound data | ||
* couldn't be allocated. An error could be returned if an invalid | ||
* recording profile name is passed in. Or an error could be returned | ||
* if the module is in playback mode. | ||
*/ | ||
Audio.prototype.startRecording = function(profile, callback) { | ||
@@ -728,71 +1233,90 @@ var self = this; | ||
// Initialize SPI to the correct settings | ||
self.spi.initialize(); | ||
self.commandQueue.place(function() { | ||
var pluginDir = __dirname + "/plugins/" + profile + ".img"; | ||
// Initialize SPI to the correct settings | ||
self.spi.initialize(); | ||
var ret = hw.audio_start_recording(this.MP3_XCS.pin, this.MP3_DREQ.pin, pluginDir, _fillBuff); | ||
var pluginDir = __dirname + "/plugins/" + profile + ".img"; | ||
if (ret < 0) { | ||
var err; | ||
var ret = hw.audio_start_recording(self.MP3_XCS.pin, self.MP3_DREQ.pin, pluginDir, _fillBuff); | ||
if (ret == -1) { | ||
err = new Error("Not able to allocate recording memory..."); | ||
if (ret < 0) { | ||
var err; | ||
if (ret == -1) { | ||
err = new Error("Not able to allocate recording memory..."); | ||
} | ||
else if (ret == -2) { | ||
err = new Error("Invalid plugin file."); | ||
} | ||
else if (ret == -3) { | ||
err = new Error("Module must be in an idle state to start recording."); | ||
} | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
} | ||
else if (ret == -2) { | ||
err = new Error("Invalid plugin file."); | ||
} | ||
else if (ret == -3) { | ||
err = new Error("Module must be in an idle state to start recording."); | ||
} | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
} | ||
else { | ||
if (callback) { | ||
callback(); | ||
} | ||
else { | ||
if (callback) { | ||
callback(); | ||
self.emit('startRecording'); | ||
} | ||
this.emit('startRecording'); | ||
} | ||
self.commandQueue.next(); | ||
}); | ||
} | ||
/* | ||
* Stop recording sound through the input. | ||
* | ||
* callback A callback to be called when recording completes. Upon | ||
* success, callback is invoked as callback(). Upon failure, | ||
* callback is invoked as callback(err) instead. | ||
* | ||
* This function may fail for a number of reasons: | ||
* | ||
* Error Could be returned if the module is not in a valid state | ||
* to stop recording (like if it's currently playing audio). | ||
*/ | ||
Audio.prototype.stopRecording = function(callback) { | ||
var self = this; | ||
var ret = hw.audio_stop_recording(); | ||
self.commandQueue.place(function() { | ||
if (ret < 0) { | ||
var err = new Error("Not in valid state to stop recording."); | ||
var ret = hw.audio_stop_recording(); | ||
if (callback) { | ||
callback(err); | ||
if (ret < 0) { | ||
var err = new Error("Not in valid state to stop recording."); | ||
if (callback) { | ||
callback(err); | ||
} | ||
} | ||
} | ||
else { | ||
else { | ||
function recStopped(length) { | ||
function recStopped(length) { | ||
process.unref(); | ||
process.unref(); | ||
// If a callback was provided, return it | ||
if (callback) { | ||
callback(); | ||
// If a callback was provided, return it | ||
if (callback) { | ||
callback(); | ||
} | ||
// Stop recording | ||
self.emit('stopRecording'); | ||
} | ||
// Stop recording | ||
self.emit('stopRecording'); | ||
} | ||
process.once('audio_recording_complete', recStopped); | ||
process.once('audio_recording_complete', recStopped); | ||
process.ref(); | ||
} | ||
process.ref(); | ||
} | ||
self.commandQueue.next(); | ||
}); | ||
} | ||
exports.use = use; |
{ | ||
"name": "audio-vs1053b", | ||
"version": "0.1.91", | ||
"version": "0.2.0", | ||
"description": "Library to run the Tessel Audio Module. Plays and records sound.", | ||
@@ -15,7 +15,8 @@ "main": "index.js", | ||
"hardware": { | ||
"./examples": "false", | ||
"./test": "false" | ||
"./examples": "false", | ||
"./test": "false" | ||
}, | ||
"author": "", | ||
"dependencies": {}, | ||
"dependencies": { | ||
"sync-queue": "0.0.1" | ||
}, | ||
"devDependencies": { | ||
@@ -22,0 +23,0 @@ "async": "^0.9.0", |
@@ -39,4 +39,4 @@ #Audio | ||
console.log("Audio module connected! Setting volume..."); | ||
// Set the volume in decibels. Around 20 is good; smaller is louder. | ||
audio.setVolume(20, function(err) { | ||
// Set the volume in decibels. Around .8 is good; 80% max volume or -25db | ||
audio.setVolume(.8, function(err) { | ||
if (err) { | ||
@@ -69,3 +69,3 @@ return console.log(err); | ||
 <a href="#api-audio-setVolume-leftChannelDb-rightChannelDb-callback-err-Set-the-output-volume-Level-is-a-Number-from-0-0-to-1-0" name="api-audio-setVolume-leftChannelDb-rightChannelDb-callback-err-Set-the-output-volume-Level-is-a-Number-from-0-0-to-1-0">#</a> audio<b>.setVolume</b>( leftChannelDb, [rightChannelDb,] callback(err) ) | ||
Set the output volume. Level is a Number from 0.0 to 1.0 | ||
Set the output volume. Level is a Number from 0.0 to 1.0 (-127dB to 0dB) | ||
@@ -76,3 +76,3 @@  <a href="#api-audio-setInput-input-callback-err-Set-the-input-to-either-lineIn-or-mic-Defaults-to-lineIn" name="api-audio-setInput-input-callback-err-Set-the-input-to-either-lineIn-or-mic-Defaults-to-lineIn">#</a> audio<b>.setInput</b>( input, callback(err) ) | ||
 <a href="#api-audio-setOutput-output-callback-err-Set-the-output-to-either-lineOut-or-headPhones-Defaults-to-lineOut" name="api-audio-setOutput-output-callback-err-Set-the-output-to-either-lineOut-or-headPhones-Defaults-to-lineOut">#</a> audio<b>.setOutput</b>( output, callback(err) ) | ||
Set the output to either 'lineOut' or 'headPhones'. Defaults to 'lineOut'. | ||
Set the output to either 'lineOut' or 'headphones'. Defaults to 'lineOut'. | ||
@@ -142,5 +142,5 @@  <a href="#api-audio-startRecording-profile-callback-err-Start-recording-sound-from-the-input-Receive-data-in-the-data-event-Callback-called-after-recording-initialized-not-stopped-quality-is-an-optional-argument-that-can-be-voice-wideband-voice-wideband-stereo-hifi-voice-or-stereo-music-Default-is-hifi-voice" name="api-audio-startRecording-profile-callback-err-Start-recording-sound-from-the-input-Receive-data-in-the-data-event-Callback-called-after-recording-initialized-not-stopped-quality-is-an-optional-argument-that-can-be-voice-wideband-voice-wideband-stereo-hifi-voice-or-stereo-music-Default-is-hifi-voice">#</a> audio<b>.startRecording</b>( [profile] callback(err) ) | ||
###Further Examples | ||
* [Audio Out No Streams](https://github.com/tessel/audio-vs1053b/blob/master/examples/audio-out-no-streams.js). This Audio Module demo sends audio from a file to Headphones/Line out without using streams.. | ||
* [Audio Out No Streams](https://github.com/tessel/audio-vs1053b/blob/master/examples/audio-out-no-streams.js). This Audio Module demo sends audio from a file to Headphones/Line out without using streams.. | ||
* [Record Sound](https://github.com/tessel/audio-vs1053b/blob/master/examples/record-sound.js). This Audio Module demo sends audio from the microphone to a file without using streams. | ||
* [Stream Audio Out](https://github.com/tessel/audio-vs1053b/blob/master/examples/stream-audio-out.js). This Audio Module demo sends audio from a file to Headphones/Line out using streams. | ||
* [Stream Audio Out](https://github.com/tessel/audio-vs1053b/blob/master/examples/stream-audio-out.js). This Audio Module demo sends audio from a file to Headphones/Line out using streams. | ||
* [Stream Sound to File](https://github.com/tessel/audio-vs1053b/blob/master/examples/stream-sound-to-file.js). This Audio Module demo takes line-in and writes it to a file using streams. | ||
@@ -147,0 +147,0 @@ |
@@ -23,3 +23,3 @@ var test = require('tinytap'); | ||
test("Changing the volume with single volume arg", function(t) { | ||
var testValue = 10; | ||
var testValue = .9; | ||
audio.setVolume(testValue, function(err) { | ||
@@ -30,4 +30,4 @@ t.equal(err, undefined, "error changing volume"); | ||
audio._readSciRegister16(0x0B, function(err, value) { | ||
t.equal(testValue, ((value >> 8)/2), 'left channel volume not set correctly'); | ||
t.equal(testValue, ((value & 0xFF)/2), 'right channel volume not set correctly'); | ||
t.equal(audio._normalizeVolume(testValue), (value >> 8), 'left channel volume not set correctly'); | ||
t.equal(audio._normalizeVolume(testValue), (value & 0xFF), 'right channel volume not set correctly'); | ||
t.end(); | ||
@@ -40,4 +40,4 @@ }); | ||
test("Changing the volume with both volume args", function(t) { | ||
var testValueLeft = 10; | ||
var testValueRight = 20; | ||
var testValueLeft = .9; | ||
var testValueRight = .8; | ||
audio.setVolume(testValueLeft, testValueRight, function(err) { | ||
@@ -48,4 +48,4 @@ t.equal(err, undefined, "error changing volume"); | ||
audio._readSciRegister16(0x0B, function(err, value) { | ||
t.equal(testValueLeft, ((value >> 8)/2), 'left channel volume not set correctly'); | ||
t.equal(testValueRight, ((value & 0xFF)/2), 'right channel volume not set correctly'); | ||
t.equal(audio._normalizeVolume(testValueLeft), (value >> 8), 'left channel volume not set correctly'); | ||
t.equal(audio._normalizeVolume(testValueRight), (value & 0xFF), 'right channel volume not set correctly'); | ||
t.end(); | ||
@@ -64,3 +64,3 @@ }); | ||
t.end(); | ||
}); | ||
}); | ||
}); | ||
@@ -78,3 +78,3 @@ }), | ||
t.end(); | ||
}); | ||
}); | ||
}); | ||
@@ -99,3 +99,3 @@ }), | ||
t.end(); | ||
}); | ||
}); | ||
}); | ||
@@ -112,3 +112,3 @@ }), | ||
t.end(); | ||
}); | ||
}); | ||
}); | ||
@@ -121,3 +121,3 @@ }), | ||
t.ok(err, 'error setting input'); | ||
t.end(); | ||
t.end(); | ||
}); | ||
@@ -151,6 +151,6 @@ }), | ||
// Clear the | ||
// Clear the | ||
clearTimeout(timeout); | ||
audio.removeAllListeners('data'); | ||
finished = true; | ||
@@ -233,3 +233,1 @@ | ||
); | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
449181
1495
2
1
+ Addedsync-queue@0.0.1
+ Addedsync-queue@0.0.1(transitive)