audio-vs1053b
Advanced tools
Comparing version 0.1.1 to 0.1.2
427
index.js
@@ -6,4 +6,5 @@ // VS1053b module | ||
var util = require('util'); | ||
var async = require('async'); | ||
var hw = process.binding('hw') | ||
var Writable = require('stream').Writable; | ||
var Readable = require('stream').Readable; | ||
@@ -28,2 +29,3 @@ // VS10xx SCI Registers | ||
var MODE_SM_RESET = 0x04; | ||
@@ -34,2 +36,10 @@ var GPIO_DIR_ADDR = 0xC017 | ||
var inputReg = 0x05, | ||
outputReg = 0x07; | ||
var _audioCallbacks = {}; | ||
var _fillBuff = new Buffer(15000); | ||
_fillBuff.fill(0); | ||
function use (hardware, next) { | ||
@@ -48,8 +58,19 @@ return new Audio(hardware, next); | ||
// Set our register select pins | ||
this.MP3_XCS = hardware.digital[1].output(true); //Control Chip Select Pin (for accessing SPI Control/Status registers) | ||
this.MP3_DCS = hardware.digital[2].output(true); //Data Chip Select / BSYNC Pin | ||
this.MP3_DREQ = hardware.digital[3].input() //Data Request Pin: Player asks for more data | ||
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 | ||
this.input = ""; | ||
this.output = ""; | ||
// Waits for the audio completion event which signifies that a buffer has finished streaming | ||
process.on('audio_playback_complete', this._handlePlaybackComplete.bind(this)); | ||
// 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)); | ||
// Waits for final flushed buffer of a recording | ||
process.on('audio_recording_complete', this._handleRecordedData.bind(this)); | ||
// Initialize the module | ||
this.initialize(callback); | ||
@@ -95,2 +116,39 @@ } | ||
Audio.prototype._handlePlaybackComplete = function(errBool, completedStream) { | ||
var self = this; | ||
if (self.lock) { | ||
self.lock.release(function(err) { | ||
if (err) { | ||
self.emit('error', err); | ||
return | ||
} | ||
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); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
Audio.prototype._handleRecordedData = function(length) { | ||
this.emit('data', _fillBuff.slice(0, length)); | ||
} | ||
Audio.prototype._failConnect = function(err, callback) { | ||
@@ -104,2 +162,62 @@ setImmediate(function() { | ||
Audio.prototype.createPlayStream = function() { | ||
var audio = this; | ||
var playStream = new Writable; | ||
// The Audio Module won't play chunks that are | ||
// less than ~3425 bytes... | ||
playStream.bufs = []; | ||
playStream.bufferedLen = 0; | ||
playStream._write = function (chunk, enc, next) { | ||
var err; | ||
this.bufs.push(chunk); | ||
this.bufferedLen += chunk.length; | ||
// Check if this chunk is too small to be played solo | ||
if (this.bufferedLen >= 10000) { | ||
var audioData = Buffer.concat(this.bufs); | ||
this.bufs = []; this.bufferedLen = 0; | ||
var ret = audio.queue(audioData); | ||
if (ret < 0) { | ||
err = new Error("Unable to queue the streamed buffer."); | ||
} | ||
} | ||
next(err); | ||
}; | ||
playStream.on('finish', function flush() { | ||
var audioData = Buffer.concat(this.bufs); | ||
this.bufs = []; this.bufferedLen = 0; | ||
if (audioData.length) { | ||
var ret = audio.queue(audioData); | ||
if (ret < 0) { | ||
err = new Error("Unable to queue the streamed buffer."); | ||
} | ||
} | ||
}); | ||
return playStream; | ||
} | ||
// Creates a Readable record stream | ||
Audio.prototype.createRecordStream = function(profile) { | ||
var audio = this; | ||
var recordStream = new Readable; | ||
var pusher = recordStream.push.bind(recordStream); | ||
audio.on('data', pusher); | ||
process.once('audio_recording_complete', recordStream.push.bind(recordStream)); | ||
recordStream._write = function() {}; | ||
audio.startRecording(profile); | ||
return recordStream; | ||
} | ||
Audio.prototype._softReset = function(callback) { | ||
@@ -109,3 +227,3 @@ this._readSciRegister16(SCI_MODE, function(err, mode) { | ||
else { | ||
this._writeSciRegister16(SCI_MODE, mode | 2, function(err) { | ||
this._writeSciRegister16(SCI_MODE, mode | MODE_SM_RESET, function(err) { | ||
if (err) { return callback && callback(err); } | ||
@@ -125,2 +243,4 @@ else { | ||
else if ((MP3Status >> 4) & 0x000F != 4){ | ||
var err = new Error("Invalid version returned from module."); | ||
return callback && callback(new Error("Invalid version returned from module.")); | ||
@@ -166,3 +286,2 @@ } | ||
//SCI consists of instruction byte, address byte, and 16-bit data word. | ||
// TODO: Error handling | ||
this._SPItransferByte(0x03, function(err) { | ||
@@ -257,3 +376,3 @@ this._SPItransferByte(addressbyte, function(err) { | ||
else { | ||
self.setInput('microphone', function(err) { | ||
self.setInput('mic', function(err) { | ||
if (err) { self._failConnect(err, callback); } | ||
@@ -286,3 +405,3 @@ else { | ||
Audio.prototype.setInput = function(input, callback) { | ||
if (input != 'lineIn' && input != 'microphone') { | ||
if (input != 'lineIn' && input != 'mic') { | ||
return callback && callback(new Error("Invalid input requested...")); | ||
@@ -293,8 +412,7 @@ } | ||
var bit = (input == 'microphone' ? 1 : 0); | ||
this._getChipGpio(function(err, gpio) { | ||
if (err) { return callback && callback(err); } | ||
else { | ||
this._setChipGpio(gpio & (bit << 5), callback); | ||
var newReg = (input === "lineIn" ? (gpio | (1 << inputReg)) : (gpio & ~(1 << inputReg))); | ||
this._setChipGpio(newReg, callback); | ||
} | ||
@@ -311,9 +429,8 @@ }.bind(this)); | ||
this.output = output; | ||
var bit = (output == 'lineOut' ? 1 : 0); | ||
this._getChipGpio(function(err, gpio) { | ||
if (err) { return callback && callback(err); } | ||
else { | ||
this._setChipGpio(gpio & (bit << 7), callback); | ||
// 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); | ||
} | ||
@@ -324,33 +441,265 @@ }.bind(this)); | ||
function Track(length, id, callback) { | ||
this._buflen = length; | ||
this.id = id; | ||
this.callback = callback; | ||
} | ||
util.inherits(Track, events.EventEmitter); | ||
Audio.prototype.play = function(buff, callback) { | ||
console.log('Loading mp3'); | ||
// Check if no buffer was passed in but a callback was | ||
// (the user would like to resume playback) | ||
var self = this; | ||
console.log('chunking', buff.length, 'bytes.'); | ||
console.log('ret: ', hw.audio_play_buffer(this.MP3_DCS.pin, this.MP3_DREQ.pin, buff, buff.length)); | ||
if (!callback && typeof buff == "function") { | ||
callback = buff; | ||
buff = new Buffer(0); | ||
} | ||
// Check if there was no buffer or callback passed in | ||
else if (!buff && !callback) { | ||
buff = new Buffer(0); | ||
} | ||
self.spi.lock(function(err, lock) { | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
// var len = buff.length; | ||
// var chunks = [], clen = 64; | ||
// var p = 0, i = 0; | ||
// while (p < len) { | ||
// chunks[i] = buff.slice(p, p + clen); | ||
// i = i + 1; | ||
// p = p + clen; | ||
// } | ||
return; | ||
} | ||
// console.log('done chunking:', chunks.length, 'chunks. Playing song...'); | ||
// Save the lock reference so we can free it later | ||
self.lock = lock; | ||
// Initialize SPI so it's set to the right settings | ||
self.spi.initialize(); | ||
// 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); | ||
// this.MP3_DCS.low(); | ||
// async.eachSeries( | ||
// chunks, | ||
// function playChunk(chunk, callback) { | ||
// while(!this.MP3_DREQ.read()){}; | ||
// this.spi.transfer(chunk, callback); | ||
// }.bind(this), | ||
// function playComplete(err) { | ||
// this.MP3_DCS.high(); | ||
// callback && callback(err); | ||
// }.bind(this) | ||
// ); | ||
var track = new Track(buff.length, streamID, callback); | ||
self._handleTrack(track); | ||
self.emit('play', track); | ||
}); | ||
} | ||
Audio.prototype._handleTrack = function(track) { | ||
// If stream id is less than zero, an error occured | ||
if (track.id < 0) { | ||
var err; | ||
if (track.id == -1) { | ||
err = new Error("Attempt to move to an invalid state."); | ||
} | ||
else if (track.id == -2) { | ||
err = new Error("Audio playback requires one GPIO Interrupt and none are available."); | ||
} | ||
else if (track.id == -3) { | ||
err = new Error("Unable to allocate memory required for transfer..."); | ||
} | ||
if (track.callback) { | ||
track.callback(err); | ||
} | ||
this.emit('error', err, track); | ||
return; | ||
} | ||
// No error occured | ||
else { | ||
// If a callback was provided | ||
if (track.callback) { | ||
// Add it to the callbacks dict | ||
_audioCallbacks[track.id] = track.callback; | ||
} | ||
} | ||
} | ||
Audio.prototype.queue = function(buff, callback) { | ||
var self = this; | ||
if (!buff) { | ||
if (callback) { | ||
callback(new Error("Must pass valid buffer to queue.")); | ||
} | ||
return; | ||
} | ||
// Initialize SPI to the correct settings | ||
self.spi.initialize(); | ||
self.spi.lock(function(err, lock) { | ||
if (err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
} | ||
else { | ||
self.lock = lock; | ||
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); | ||
} | ||
}); | ||
} | ||
Audio.prototype.pause = function(callback) { | ||
var err; | ||
var ret = hw.audio_pause_buffer(); | ||
if (ret < 0) { | ||
err = new Error("A buffer is not being played."); | ||
this.emit('error', 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 | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
}); | ||
} | ||
// If there is no lock, just call the callback | ||
else { | ||
if (callback) { | ||
callback(err); | ||
} | ||
} | ||
} | ||
Audio.prototype.stop = function(callback) { | ||
var err; | ||
var ret = hw.audio_stop_buffer(); | ||
if (ret < 0) { | ||
err = new Error("Not in a valid state to call stop."); | ||
this.emit('error', 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 | ||
if (callback) { | ||
callback(err); | ||
} | ||
return; | ||
}); | ||
} | ||
// If there is no lock, just call the callback | ||
else { | ||
if (callback) { | ||
callback(err); | ||
} | ||
} | ||
} | ||
Audio.prototype.availableRecordingProfiles = function() { | ||
return [ | ||
'voice', | ||
'wideband-voice', | ||
'wideband-stereo', | ||
'hifi-voice', | ||
'stereo-music' | ||
]; | ||
} | ||
Audio.prototype.startRecording = function(profile, callback) { | ||
var self = this; | ||
if (!callback && typeof profile == "function") { | ||
callback = profile; | ||
profile = "hifi-voice"; | ||
} | ||
else if (!profile && !callback) { | ||
profile = "hifi-voice"; | ||
} | ||
if (self.availableRecordingProfiles().indexOf(profile) == -1) { | ||
var err = new Error("Invalid profile name. See audio.availableRecordingProfiles()"); | ||
if (callback) { | ||
callback(err); | ||
} | ||
self.emit('error', err); | ||
return; | ||
} | ||
// Initialize SPI to the correct settings | ||
self.spi.initialize(); | ||
var pluginDir = __dirname + "/plugins/" + profile + ".img"; | ||
var ret = hw.audio_start_recording(this.MP3_XCS.pin, this.MP3_DREQ.pin, pluginDir, _fillBuff); | ||
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); | ||
} | ||
this.emit('error', err); | ||
return; | ||
} | ||
else { | ||
if (callback) { | ||
callback(); | ||
} | ||
this.emit('startRecording'); | ||
} | ||
} | ||
Audio.prototype.stopRecording = function(callback) { | ||
var self = this; | ||
process.once('audio_recording_complete', function recStopped(length) { | ||
// If a callback was provided, return it | ||
if (callback) { | ||
callback(); | ||
} | ||
// Stop recording | ||
self.emit('stopRecording'); | ||
}); | ||
var ret = hw.audio_stop_recording(); | ||
if (ret < 0) { | ||
var err = new Error("Not in valid state to stop recording."); | ||
if (callback) { | ||
callback(err); | ||
} | ||
this.emit('error', err); | ||
return; | ||
} | ||
} | ||
exports.use = use; |
{ | ||
"name": "audio-vs1053b", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "", | ||
@@ -11,9 +11,6 @@ "main": "index.js", | ||
"author": "", | ||
"license": "BSD-2-Clause", | ||
"dependencies": { | ||
"async": "*" | ||
}, | ||
"devDependencies": { | ||
"tinytap": "~0.0.2" | ||
} | ||
}, | ||
"license": "BSD-2-Clause" | ||
} |
@@ -7,2 +7,12 @@ #Audio Module | ||
## Limitations | ||
The current version of the Tessel runtime is too slow to play audio files smoothly. That means we wrote a custom C shim that handles most of the playback and recording of data. There are several consequences of the C shim: | ||
* Any other modules that use SPI for communication will be blocked while the audio module is playing a buffer. | ||
* You can only have one audio module attached to Tessel at a time. | ||
* Updates to the Audio Module driver must be released in both firmware and this npm repo. | ||
It sucks but we're expecting major runtime speed improvements to render the C shim uncessesary within the next couple months. | ||
##Example | ||
@@ -16,4 +26,10 @@ 1. Writing mic data to a file (w/out streams) | ||
// Start recording data for a second into a file | ||
audio.setInput('microphone', function(err) { | ||
audio.setInput('mic', function(err) { | ||
var chunks = []; | ||
audio.on('data', function(data) { | ||
chunks.push(data); | ||
}); | ||
// Start the recording | ||
@@ -24,5 +40,5 @@ audio.startRecording(function(err) { | ||
// Stop recording | ||
audio.stopRecording(function(err, oggBuffer) { | ||
audio.stopRecording(function(err) { | ||
// Write the buffer to a file | ||
fs.writeFile("micdata", oggBuffer, function(err) { | ||
fs.writeFile("micdata", Buffer.concat(chunks), function(err) { | ||
console.log("Wrote to a file"); | ||
@@ -44,12 +60,9 @@ }); | ||
// Start recording data for a second into a file | ||
audio.setInput('microphone', function(err) { | ||
audio.setInput('line-in', function(err) { | ||
// Open a stream to a file | ||
var file = fs.createWriteStream('lineInData.ogg'); | ||
// Create a readable stream of incoming data | ||
var soundData = audio.createReadStream(); | ||
var soundData = audio.createRecordStream(); | ||
// Pipe data to the file | ||
soundData.pipe(file); | ||
// Enable sound input | ||
audio.startRecording(); | ||
}); | ||
@@ -59,3 +72,3 @@ }); | ||
``` | ||
3. Output audio on the headphone Jack | ||
3. Output audio on the headphone Jack (w/o streams) | ||
```.js | ||
@@ -76,3 +89,17 @@ var tessel = require('tessel'); | ||
``` | ||
4. Output audio on the headphone Jack (with streams) | ||
```.js | ||
var tessel = require('tessel'); | ||
var fs = require('fs'); | ||
var audio = require('audio-vs1053b').use(tessel.port('a'), function(err) { | ||
// Start recording data for a second into a file | ||
audio.setOutput('headphone', function(err) { | ||
// Open a file | ||
fs.createReadStream('rayman.ogg').pipe(audio.createPlayStream()); | ||
}); | ||
}); | ||
``` | ||
##API | ||
@@ -86,3 +113,3 @@ | ||
// Set the input to either 'lineIn' or 'microphone'. Defaults to 'lineIn'. | ||
// Set the input to either 'lineIn' or 'mic'. Defaults to 'lineIn'. | ||
audio.setInput( input, function(err) {...} ); | ||
@@ -93,10 +120,12 @@ | ||
// Start recording sound from the input. | ||
audio.startRecording( function(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'. | ||
audio.startRecording([profile] function(err) {...} ); | ||
// Stop recording sound and return an OGG-encoded buffer | ||
audio.stopRecording( function(err, oggBuff) {...} ); | ||
// Stop recording sound (note that may receive one more 'data' event before this completes when the buffer is flushed.) | ||
audio.stopRecording( function(err) {...} ); | ||
// Play a buffer | ||
audio.play( audioBuff, function(err) {...} ); | ||
// Play a buffer. If no buffer is passed in, the module | ||
// will attempt to resume a buffer that was paused. | ||
audio.play( [audioBuff], function(err) {...} ); | ||
@@ -110,7 +139,10 @@ // Pause the buffer | ||
// Returns a stream that a buffer can be piped into to play audio | ||
audio.createWriteableStream(); | ||
audio.createPlayStream(); | ||
// Returns a readable stream of mic data | ||
audio.createReadableStream() | ||
audio.createRecordStream() | ||
// Returns an array of available profiles | ||
audio.availableRecordingProfiles(); | ||
``` | ||
@@ -140,2 +172,5 @@ | ||
// Received recorded data | ||
audio.on('data', function(audioBuff) {...} ); | ||
// Stopped recording on the input | ||
@@ -147,8 +182,11 @@ audio.on('stopRecording', function() {...} ); | ||
// The buffer was paused | ||
// Playback was paused | ||
audio.on('pause', function() {...} ); | ||
// The buffer was stopped | ||
// Playback was stopped | ||
audio.on('stop', function() {...} ); | ||
// The buffer finished playing | ||
audio.on('end', function(err) {...}) | ||
``` |
189
test.js
var tessel = require('tessel'); | ||
var fs = require('fs'); | ||
var audio = require('./').use(tessel.port('a')); | ||
var song = fs.readFileSync('/app/playback/sample.mp3'); | ||
var audio = require('./').use(tessel.port['A']); | ||
var stream = require('stream'); | ||
var filename = process.argv[2] || 'audio-recording.ogg'; | ||
console.log("Saving to filename:", filename); | ||
var datas = []; | ||
audio.on('ready', function() { | ||
console.log("Ready to go!"); | ||
// audio.setVolume(2, 2, function(err) { | ||
// if (err) return console.log('err setting volume', err); | ||
var song = fs.readFileSync('/app/sample.mp3'); | ||
audio.on('data', function weRecorded(data) { | ||
console.log('got this recording data!', data.length);; | ||
datas.push(data); | ||
}) | ||
audio.on('error', function(err) { | ||
console.log("ERROR:", err); | ||
}) | ||
audio.on('startRecording', function() { | ||
console.log('started recording!'); | ||
}); | ||
audio.on('stopRecording', function() { | ||
console.log('stopped recording!'); | ||
var rec = Buffer.concat(datas); | ||
console.log('playing len', rec.length); | ||
process.sendfile(filename, rec); | ||
// fs.writeFileSync(filename, rec); | ||
// fs.createReadStream(filename).pipe(audio.createPlayStream()); | ||
}); | ||
function testOutputs() { | ||
audio.setInput('lineIn', function(err) { | ||
console.log('line in is set', err); | ||
audio.startRecording('voice', function(err) { | ||
console.log('started recording'); | ||
setTimeout(audio.stopRecording.bind(audio), 12000); | ||
}); | ||
}); | ||
} | ||
function testInputs() { | ||
audio.setOutput('lineOut', function(err) { | ||
console.log('set to line in', err); | ||
audio.play(song, function(err) { | ||
console.log('finished playing song', err); | ||
console.log('finished with line in.'); | ||
audio.setOutput('headphones', function(err) { | ||
console.log('set to phones', err); | ||
audio.play(song); | ||
}); | ||
}); | ||
}); | ||
} | ||
function testSwitchPlayRecord() { | ||
console.log('playing song.'); | ||
audio.play(song, function(err) { | ||
if (err) return console.log("err playing..", err); | ||
else { | ||
console.log('finished playing...'); | ||
audio.startRecording(); | ||
} | ||
}) | ||
} | ||
function testSwitchRecordPlay() { | ||
console.log('recording song.'); | ||
audio.startRecording(function recStarted(err) { | ||
if (err) return console.log("err starting recording..", err); | ||
}); | ||
setTimeout(function() { | ||
console.log('calling stop recording...'); | ||
audio.stopRecording(function recStopped(err) { | ||
if (err) return console.log("err stopping recording..", err); | ||
else { | ||
audio.play(song); | ||
} | ||
}) | ||
}, 3000); | ||
} | ||
function testRecording() { | ||
audio.setInput('mic', function() { | ||
audio.startRecording('voice', function() { | ||
setTimeout(function stopRecording() { | ||
audio.stopRecording(function stopped() { | ||
console.log("Stop recording callback called..."); | ||
}) | ||
}, 4000); | ||
}); | ||
}) | ||
} | ||
function testPlayback() { | ||
var ret = audio.play(song, function(err) { | ||
if (err) { | ||
console.log("error playing song: ", err); | ||
} | ||
else { | ||
console.log("Done playing the song"); | ||
} | ||
}); | ||
} | ||
function testQueue() { | ||
audio.queue(song); | ||
audio.queue(song); | ||
audio.queue(song); | ||
audio.queue(song); | ||
} | ||
function testPlayStop() { | ||
audio.on('play', audio.stop.bind(audio, undefined)); | ||
audio.play(song); | ||
} | ||
function testPlayQueue() { | ||
audio.play(song); | ||
audio.queue(song); | ||
audio.queue(song); | ||
audio.queue(song); | ||
audio.queue(song); | ||
} | ||
function testPlayStream() { | ||
var file = fs.createReadStream('/app/playback/rayman.ogg'); | ||
file.pipe(audio.createPlayStream()); | ||
} | ||
function testRecordStream() { | ||
var rec = audio.createRecordStream("voice"); | ||
var file = fs.createWriteStream('rec.ogg'); | ||
rec.pipe(file); | ||
setTimeout(function() { | ||
audio.stopRecording(function() { | ||
console.log("Stop recording callback after stream called..."); | ||
rec.unpipe(file); | ||
}); | ||
// }) | ||
}); | ||
}, 4000); | ||
} | ||
audio.on('error', function(err) { | ||
console.log("Failed to connect", err); | ||
}) | ||
function testPlayStreamSmallChunks(chunkSize) { | ||
var chunk = chunkSize; | ||
var incr = Math.floor(song.length/chunk); | ||
console.log('length', song.length, 'floor', Math.floor(song.length/chunk)); | ||
var rs = new stream.Readable; | ||
setInterval(function(){}, 20000); | ||
for (var i = 0; i < incr; i++) { | ||
var pos = chunk * i; | ||
rs.push(song.slice(pos, pos + chunk)); | ||
} | ||
if (song.length%chunk) { | ||
var pos = chunk * incr; | ||
rs.push(song.slice(pos, pos + song.length%chunk)); | ||
} | ||
rs.push(null); | ||
rs.pipe(audio.createPlayStream()) | ||
} | ||
audio.on('ready', function() { | ||
console.log("Ready to go!"); | ||
audio.setVolume(20, 20, function(e) { | ||
// testOutputs(); | ||
// testInputs(); | ||
// testPlayStreamSmallChunks(5000); | ||
// testRecordStream(); | ||
// testPlayStream(); | ||
// testSwitchPlayRecord(); | ||
// testSwitchRecordPlay(); | ||
// testQueue(); | ||
// testPlayQueue(); | ||
testRecording(); | ||
// testPlayStop(); | ||
// testPlayback(); | ||
}); | ||
}); |
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
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
240906
0
12
773
1
181
4
2
- Removedasync@*
- Removedasync@3.2.6(transitive)