-
-
Notifications
You must be signed in to change notification settings - Fork 152
/
Copy pathdeviceDiscovery.js
109 lines (104 loc) · 3.41 KB
/
deviceDiscovery.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* Sonos library to control (almost) everything from your sonos devices
* @module sonos
* @requires 'events'
* @requires 'dgram'
* @requires './sonos'
*/
const dgram = require('dgram')
const util = require('util')
const EventEmitter = require('events').EventEmitter
const Sonos = require('./sonos').Sonos
/**
* Create a new instance of DeviceDiscovery
* @class DeviceDiscovery
* @emits 'DeviceAvailable' on a Sonos Component Discovery
*/
var DeviceDiscovery = function DeviceDiscovery (options) {
var self = this
self.foundSonosDevices = {}
self.onTimeout = function () {
clearTimeout(self.pollTimer)
}
var PLAYER_SEARCH = Buffer.from(['M-SEARCH * HTTP/1.1',
'HOST: 239.255.255.250:1900',
'MAN: ssdp:discover',
'MX: 1',
'ST: urn:schemas-upnp-org:device:ZonePlayer:1'].join('\r\n'))
var sendDiscover = function () {
['239.255.255.250', '255.255.255.255'].map(function (addr) {
self.socket.send(PLAYER_SEARCH, 0, PLAYER_SEARCH.length, 1900, addr)
})
// Periodically send discover packet to find newly added devices
self.pollTimer = setTimeout(sendDiscover, 10000)
// Remove the on timeout listener and add back in every iteration
self.removeListener('timeout', self.onTimeout)
self.on('timeout', self.onTimeout)
}
this.socket = dgram.createSocket('udp4', function (buffer, rinfo) {
buffer = buffer.toString()
if (buffer.match(/.+Sonos.+/)) {
var modelCheck = buffer.match(/SERVER.*\((.*)\)/)
var model = (modelCheck.length > 1 ? modelCheck[1] : null)
var addr = rinfo.address
if (!(addr in self.foundSonosDevices)) {
var sonos = self.foundSonosDevices[addr] = new Sonos(addr)
self.emit('DeviceAvailable', sonos, model)
}
}
})
this.socket.on('close', function () {
if (self.searchTimer) {
clearTimeout(self.searchTimer)
}
clearTimeout(self.pollTimer)
})
this.socket.on('error', function (err) {
self.emit('error', err)
})
this.socket.bind(options, function () {
self.socket.setBroadcast(true)
sendDiscover()
})
if (options.timeout) {
self.searchTimer = setTimeout(function () {
self.socket.close()
self.emit('timeout')
}, options.timeout)
}
return this
}
util.inherits(DeviceDiscovery, EventEmitter)
/**
* Destroys DeviceDiscovery class, stop searching, clean up
* @param {Function} callback ()
*/
DeviceDiscovery.prototype.destroy = function (callback) {
clearTimeout(this.searchTimer)
clearTimeout(this.pollTimer)
this.socket.close(callback)
}
/**
* Create a DeviceDiscovery Instance (emits 'DeviceAvailable' with a found Sonos Component)
* @param {Object} options Optional Options to control search behavior.
* Set 'timeout' to how long to search for devices
* (in milliseconds).
* Set 'port' to use a specific inbound UDP port,
* rather than a randomly assigned one
* @param {Function} listener Optional 'DeviceAvailable' listener (sonos)
* @return {DeviceDiscovery}
*/
var deviceDiscovery = function (options, listener) {
if (typeof options === 'function') {
listener = options
options = null
}
options = options || {}
listener = listener || null
var search = new DeviceDiscovery(options)
if (listener !== null) {
search.on('DeviceAvailable', listener)
}
return search
}
module.exports = deviceDiscovery