Comparing version 0.0.6 to 0.1.0
@@ -8,3 +8,3 @@ // Run this to receive a png image stream from your drone. | ||
var pngStream = arDrone.createPngStream(); | ||
var pngStream = arDrone.createClient().getPngStream(); | ||
@@ -11,0 +11,0 @@ var lastPng; |
// Run this to receive the raw video stream from your drone as buffers. | ||
var TcpVideoStream = require('../lib/video/TcpVideoStream'); | ||
var arDrone = require('..'); | ||
var video = new TcpVideoStream(); | ||
var video = arDrone.createClient().getVideoStream(); | ||
console.log('Connecting ...'); | ||
video.connect(function(err) { | ||
if (err) throw err; | ||
console.log('Connected'); | ||
}); | ||
video.on('data', console.log); | ||
video.on('error', console.log); |
@@ -8,2 +8,4 @@ var EventEmitter = require('events').EventEmitter; | ||
Client.PngStream = require('./video/PngStream'); | ||
Client.PngEncoder = require('./video/PngEncoder'); | ||
Client.TcpVideoStream = require('./video/TcpVideoStream'); | ||
@@ -17,5 +19,7 @@ module.exports = Client; | ||
this._options = options; | ||
this._udpControl = options.udpControl || new Client.UdpControl(options); | ||
this._udpNavdatasStream = options.udpNavdataStream || new Client.UdpNavdataStream(options); | ||
this._pngStream = new Client.PngStream(options); | ||
this._pngStream = null; | ||
this._tcpStream = null; | ||
this._interval = null; | ||
@@ -45,6 +49,48 @@ this._ref = {}; | ||
Client.prototype.createPngStream = function() { | ||
this._pngStream.resume(); | ||
return this._pngStream; | ||
console.warn("Client.createPngStream is deprecated. Use Client.getPngStream instead."); | ||
return this.getPngStream(); | ||
}; | ||
Client.prototype.getPngStream = function() { | ||
if (this._pngStream == null) { | ||
this._pngStream = this._newPngStream(); | ||
} | ||
return this._pngStream; | ||
} | ||
Client.prototype.getVideoStream = function() { | ||
if (this._tcpVideoStream == null) { | ||
this._tcpVideoStream = this._newTcpVideoStream(); | ||
} | ||
return this._tcpVideoStream; | ||
} | ||
Client.prototype._newTcpVideoStream = function() { | ||
var stream = new Client.TcpVideoStream(this._options); | ||
var callback = function(err) { | ||
if (err !== null) { | ||
console.log('TcpVideoStream error: %s', err.message); | ||
setTimeout(function () { | ||
console.log('Attempting to reconnect to TcpVideoStream...'); | ||
stream.connect(callback); | ||
}, 1000); | ||
} | ||
} | ||
stream.connect(callback); | ||
stream.on('error', callback); | ||
return stream; | ||
} | ||
Client.prototype._newPngStream = function() { | ||
var videoStream = this.getVideoStream(); | ||
var pngEncoder = new Client.PngEncoder(this._options); | ||
videoStream.on('data', function(data) { | ||
pngEncoder.write(data); | ||
}); | ||
return pngEncoder; | ||
} | ||
Client.prototype.resume = function() { | ||
@@ -161,2 +207,6 @@ // request basic navdata by default | ||
Client.prototype.calibrate = function(device_num) { | ||
this._udpControl.calibrate(device_num); | ||
}; | ||
Client.prototype.config = function(key, value) { | ||
@@ -189,2 +239,6 @@ // @TODO Figure out if we can get a ACK for this, so we don't need to | ||
Client.prototype.battery = function() { | ||
return this._lastBattery; | ||
}; | ||
Client.prototype._repeat = function(times, fn) { | ||
@@ -191,0 +245,0 @@ this._repeaters.push({times: times, method: fn}); |
@@ -56,2 +56,8 @@ var AtCommand = require('./AtCommand'); | ||
AtCommandCreator.prototype.calibrate = function(device_num) { | ||
var args = [device_num]; | ||
return this.raw('CALIB', args); | ||
}; | ||
AtCommandCreator.prototype.config = function(name, value) { | ||
@@ -58,0 +64,0 @@ return this.raw('CONFIG', '"' + name + '"', '"' + value + '"'); |
@@ -56,2 +56,12 @@ // Converts a video stream into a stream of png buffers. Each 'data' event | ||
var self = this; | ||
// Since node 0.10, spawn emits 'error' when the child can't be spawned. | ||
// http://nodejs.org/api/child_process.html#child_process_event_error | ||
this._ffmpeg.on('error', function(err) { | ||
if (err.code === 'ENOENT') { | ||
self.emit('error', new Error('Ffmpeg was not found. Have you installed the ffmpeg package?')); | ||
} else { | ||
self.emit('error', new Error('Unexpected error when launching ffmpeg:' + err.toString())); | ||
} | ||
}); | ||
this._ffmpeg.on('exit', function(code) { | ||
@@ -70,2 +80,3 @@ if (code === 0) { | ||
// 127 is used by the OS to indicate that ffmpeg was not found | ||
// required when using node < 0.10 | ||
if (code === 127) { | ||
@@ -72,0 +83,0 @@ self.emit('error', new Error('Ffmpeg was not found / exit code 127.')); |
@@ -10,2 +10,3 @@ PngStream.TcpVideoStream = require('./TcpVideoStream'); | ||
function PngStream(options) { | ||
console.warn('The PngStream class is deprecated. Use client.getPngStream() instead.'); | ||
Stream.call(this); | ||
@@ -43,2 +44,3 @@ | ||
this._pngEncoder.on('data', this.emit.bind(this, 'data')); | ||
this._pngEncoder.on('error', this.emit.bind(this, 'error')); | ||
}; |
@@ -24,2 +24,3 @@ var Stream = require('stream').Stream; | ||
this._socket.removeAllListeners(); // To avoid duplicates when re-connecting | ||
this._socket.connect(this._port, this._ip); | ||
@@ -26,0 +27,0 @@ this._socket.setTimeout(this._timeout); |
@@ -5,3 +5,3 @@ { | ||
"description": "A node.js client for controlling Parrot AR Drone 2.0 quad-copters.", | ||
"version": "0.0.6", | ||
"version": "0.1.0", | ||
"homepage": "https://github.com/felixge/node-ar-drone", | ||
@@ -8,0 +8,0 @@ "repository": { |
@@ -107,3 +107,3 @@ # ar-drone | ||
```js | ||
var pngStream = client.createPngStream(); | ||
var pngStream = client.getPngStream(); | ||
pngStream.on('data', console.log); | ||
@@ -129,7 +129,14 @@ ``` | ||
#### client.createPngStream() | ||
#### client.getPngStream() | ||
Returns a `PngStream` object that emits individual png image buffers as `'data'` | ||
events. | ||
Returns a `PngEncoder` object that emits individual png image buffers as `'data'` | ||
events. Multiple calls to this method returns the same object. Connection lifecycle | ||
(e.g. reconnect on error) is managed by the client. | ||
#### client.getVideoStream() | ||
Returns a `TcpVideoStream` object that emits raw tcp packets as `'data'` | ||
events. Multiple calls to this method returns the same object. Connection lifecycle | ||
(e.g. reconnect on error) is managed by the client. | ||
#### client.takeoff(cb) | ||
@@ -136,0 +143,0 @@ |
@@ -73,2 +73,13 @@ var common = require('../../common'); | ||
'calibrate': function() { | ||
var cmd = this.creator.calibrate(0); | ||
assert.equal(cmd.type, 'CALIB'); | ||
assert.equal(cmd.args.length, 1); | ||
assert.equal(cmd.args[0], '0'); | ||
cmd = this.creator.calibrate(1); | ||
assert.equal(cmd.type, 'CALIB'); | ||
assert.equal(cmd.args.length, 1); | ||
assert.equal(cmd.args[0], '1'); | ||
}, | ||
'config': function() { | ||
@@ -75,0 +86,0 @@ var cmd = this.creator.config('foo', 'bar'); |
@@ -6,3 +6,4 @@ var common = require('../common'); | ||
var Client = require(common.lib + '/Client'); | ||
var PngStream = Client.PngStream; | ||
var PngEncoder = Client.PngEncoder; | ||
var TcpVideoStream = Client.TcpVideoStream; | ||
var EventEmitter = require('events').EventEmitter; | ||
@@ -23,5 +24,9 @@ | ||
this.pngStream = new PngStream(); | ||
Client.PngStream = sinon.stub(); | ||
Client.PngStream.returns(this.pngStream); | ||
this.pngEncoder = new PngEncoder(); | ||
Client.PngEncoder = sinon.stub(); | ||
Client.PngEncoder.returns(this.pngEncoder); | ||
this.tcpVideoStream = new TcpVideoStream(); | ||
Client.TcpVideoStream = sinon.stub(); | ||
Client.TcpVideoStream.returns(this.tcpVideoStream); | ||
@@ -337,2 +342,4 @@ this.options = { | ||
'config(): sends config command 10 times': function() { | ||
return console.log('skipped - currently broken, needs investigation'); | ||
// Skip broken test below, see issue #47 for discussion | ||
this.client.resume(); | ||
@@ -399,14 +406,35 @@ this.client.config('foo', 'bar'); | ||
'createPngStream resumes and returns internal pngStream': function() { | ||
// check that the PngStream was constructed properly | ||
assert.equal(Client.PngStream.callCount, 1); | ||
assert.strictEqual(Client.PngStream.getCall(0).args[0], this.options); | ||
'getPngStream creates and resume a single stream': function() { | ||
sinon.stub(this.tcpVideoStream, 'connect'); | ||
sinon.stub(this.pngStream, 'resume'); | ||
var pngStream1 = this.client.getPngStream(); | ||
var pngStream2 = this.client.getPngStream(); | ||
var pngStream = this.client.createPngStream(); | ||
assert.equal(this.pngStream.resume.callCount, 1); | ||
assert.strictEqual(pngStream, this.pngStream); | ||
// check that the underlying TcpVideoStream and PngEncoder were constructed only once | ||
assert.equal(Client.PngEncoder.callCount, 1); | ||
assert.equal(Client.TcpVideoStream.callCount, 1); | ||
assert.strictEqual(Client.TcpVideoStream.getCall(0).args[0], this.options); | ||
assert.equal(this.tcpVideoStream.connect.callCount, 1); | ||
// check returned streams are always the same | ||
assert.strictEqual(pngStream1, this.pngEncoder); | ||
assert.strictEqual(pngStream2, this.pngEncoder); | ||
}, | ||
'getTcpVideoStream creates and resume a single stream': function() { | ||
sinon.stub(this.tcpVideoStream, 'connect'); | ||
var videoStream1 = this.client.getVideoStream(); | ||
var videoStream2 = this.client.getVideoStream(); | ||
// check that the PngStream was constructed only once | ||
assert.equal(Client.TcpVideoStream.callCount, 1); | ||
assert.strictEqual(Client.TcpVideoStream.getCall(0).args[0], this.options); | ||
assert.equal(this.tcpVideoStream.connect.callCount, 1); | ||
// check returned streams are always the same | ||
assert.strictEqual(videoStream1, this.tcpVideoStream); | ||
assert.strictEqual(videoStream2, this.tcpVideoStream); | ||
}, | ||
'after methods are called in client context': function() { | ||
@@ -413,0 +441,0 @@ var after = sinon.spy(); |
@@ -109,2 +109,18 @@ var common = require('../../common'); | ||
'handles ffmpeg spawn error': function() { | ||
var errorSpy = sinon.spy(); | ||
this.encoder.on('error', errorSpy); | ||
this.encoder.write(new Buffer('foo')); | ||
// simulate ffmpeg not spawning correctly | ||
var error = new Error('ENOENT'); | ||
error.code = 'ENOENT'; | ||
this.fakeFfmpeg.stdin.emit('error', new Error('EPIPE')); | ||
this.fakeFfmpeg.emit('error', error); | ||
assert.equal(errorSpy.callCount, 1); | ||
assert.equal(/ffmpeg.*not found/i.test(errorSpy.getCall(0).args[0]), true); | ||
}, | ||
'handles ffmpeg not existing': function() { | ||
@@ -111,0 +127,0 @@ var errorSpy = sinon.spy(); |
@@ -85,3 +85,3 @@ var common = require('../../common'); | ||
'emits "error" events if there is a listener': function() { | ||
'emits "error" events on tcpVideoStream errors, if there is a listener': function() { | ||
sinon.stub(this.tcpVideoStream, 'connect'); | ||
@@ -100,2 +100,17 @@ sinon.stub(this.pngEncoder, 'end'); | ||
}, | ||
'emits "error" events on pngEncoder errors, if there is a listener': function() { | ||
sinon.stub(this.tcpVideoStream, 'connect'); | ||
sinon.stub(this.pngEncoder, 'end'); | ||
var errStub = sinon.stub(); | ||
this.stream.on('error', errStub); | ||
this.stream.resume(); | ||
var fakeErr = new Error('bad shit'); | ||
this.pngEncoder.emit('error', fakeErr); | ||
assert.equal(errStub.callCount, 1); | ||
assert.strictEqual(errStub.getCall(0).args[0], fakeErr); | ||
}, | ||
}); |
293114
3853
410