@ciphore/radiocli 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/CHANGELOG.md +147 -2
  2. package/CONTRIBUTING.md +46 -6
  3. package/README.md +108 -209
  4. package/SECURITY.md +23 -1
  5. package/dist/agent/alarm-service.js +10 -7
  6. package/dist/agent/cli.js +16 -1
  7. package/dist/agent/command-schema.js +47 -0
  8. package/dist/agent/headless-host.js +234 -67
  9. package/dist/agent/launcher.js +7 -67
  10. package/dist/agent/mcp-install.js +15 -15
  11. package/dist/agent/mcp-server.js +10 -5
  12. package/dist/agent/service.js +74 -39
  13. package/dist/agent/session.js +227 -53
  14. package/dist/agent/tui-session.js +213 -0
  15. package/dist/alarms/active-session.js +9 -12
  16. package/dist/alarms/cli.js +19 -3
  17. package/dist/alarms/guard.js +79 -36
  18. package/dist/alarms/inhibitor.js +27 -22
  19. package/dist/alarms/occurrence-cache.js +25 -0
  20. package/dist/alarms/power-guard-store.js +2 -10
  21. package/dist/alarms/runner.js +140 -45
  22. package/dist/alarms/schedule.js +37 -2
  23. package/dist/alarms/scheduler.js +202 -52
  24. package/dist/alarms/setup-verification.js +1 -2
  25. package/dist/alarms/system-volume-linux.js +160 -0
  26. package/dist/alarms/system-volume-ownership.js +335 -0
  27. package/dist/alarms/system-volume.js +188 -26
  28. package/dist/alarms/terminal-launcher.js +76 -136
  29. package/dist/alarms/tui-presence.js +2 -4
  30. package/dist/cli/arguments.js +212 -0
  31. package/dist/cli/completion.js +44 -0
  32. package/dist/cli/doctor.js +156 -0
  33. package/dist/cli/interactive.js +79 -0
  34. package/dist/cli/listener.js +227 -0
  35. package/dist/cli/output.js +121 -0
  36. package/dist/cli/render-tui.js +34 -0
  37. package/dist/cli.js +198 -154
  38. package/dist/platform/capabilities.js +60 -0
  39. package/dist/platform/desktop-media.js +61 -0
  40. package/dist/platform/desktop.js +36 -0
  41. package/dist/platform/diagnostics.js +273 -0
  42. package/dist/{player/command.js → platform/executables.js} +43 -9
  43. package/dist/platform/ipc.js +14 -0
  44. package/dist/platform/json-worker.js +111 -0
  45. package/dist/platform/launch-command.js +138 -0
  46. package/dist/platform/loopback.js +44 -0
  47. package/dist/platform/mpris.js +356 -0
  48. package/dist/platform/network.js +380 -0
  49. package/dist/platform/omarchy.js +147 -0
  50. package/dist/platform/packages.js +222 -0
  51. package/dist/platform/paths.js +40 -0
  52. package/dist/platform/runtime.js +67 -0
  53. package/dist/platform/shell.js +24 -0
  54. package/dist/platform/storage.js +48 -0
  55. package/dist/platform/support.js +214 -0
  56. package/dist/platform/terminal.js +63 -0
  57. package/dist/platform/terminals.js +223 -0
  58. package/dist/player/airplay-discovery.js +145 -60
  59. package/dist/player/airplay-policy.js +15 -0
  60. package/dist/player/airplay-process.js +63 -0
  61. package/dist/player/airplay-readiness.js +42 -0
  62. package/dist/player/airplay-sender-health.js +49 -49
  63. package/dist/player/airplay-sender-package.js +5 -0
  64. package/dist/player/airplay-sender-patch.js +102 -4
  65. package/dist/player/airplay-setup.js +51 -0
  66. package/dist/player/airplay-worker.js +97 -41
  67. package/dist/player/backend-install.js +17 -95
  68. package/dist/player/command-diagnostics.js +2 -2
  69. package/dist/player/ffmpeg-input.js +37 -0
  70. package/dist/player/mpv-desktop-media.js +194 -0
  71. package/dist/player/mpv-ipc-client.js +52 -2
  72. package/dist/player/player-controller.js +569 -82
  73. package/dist/player/radio-engine.js +282 -0
  74. package/dist/playlists/playlist.js +18 -16
  75. package/dist/providers/cache.js +293 -99
  76. package/dist/providers/discovery-session.js +111 -0
  77. package/dist/providers/provider-manager.js +106 -28
  78. package/dist/providers/radio-browser.js +418 -89
  79. package/dist/providers/radio-garden.js +18 -23
  80. package/dist/setup-playback.js +152 -0
  81. package/dist/setup.js +163 -168
  82. package/dist/storage/file-lock.js +113 -0
  83. package/dist/storage/read-settings.js +33 -0
  84. package/dist/storage/replace-file.js +20 -0
  85. package/dist/storage/repository.js +247 -0
  86. package/dist/storage/station-identity.js +21 -0
  87. package/dist/storage/station-schema.js +27 -0
  88. package/dist/storage/store.js +333 -107
  89. package/dist/streams/import-stream.js +163 -0
  90. package/dist/ui/AdaptiveContent.js +49 -32
  91. package/dist/ui/App.js +822 -481
  92. package/dist/ui/AppContent.js +5 -5
  93. package/dist/ui/airplay-settings.js +12 -5
  94. package/dist/ui/app-state.js +8 -1
  95. package/dist/ui/ascii.js +11 -2
  96. package/dist/ui/bidi-ranges.js +45 -0
  97. package/dist/ui/components/AdaptiveMarquee.js +20 -10
  98. package/dist/ui/components/Logo.js +5 -2
  99. package/dist/ui/components/Menu.js +2 -2
  100. package/dist/ui/components/ScreenHeader.js +1 -1
  101. package/dist/ui/components/StationList.js +6 -4
  102. package/dist/ui/components/TopTabs.js +1 -1
  103. package/dist/ui/display-context.js +8 -11
  104. package/dist/ui/format.js +37 -4
  105. package/dist/ui/help-content.js +9 -6
  106. package/dist/ui/layout.js +5 -2
  107. package/dist/ui/page-footer.js +3 -3
  108. package/dist/ui/rtl-output.js +137 -0
  109. package/dist/ui/screen-items.js +12 -6
  110. package/dist/ui/screen-meta.js +1 -1
  111. package/dist/ui/screens/AirPlayCodeScreen.js +6 -2
  112. package/dist/ui/screens/AirPlaySettingsScreen.js +10 -6
  113. package/dist/ui/screens/AlarmsScreen.js +5 -2
  114. package/dist/ui/screens/ExploreScreen.js +2 -1
  115. package/dist/ui/screens/HelpScreen.js +8 -4
  116. package/dist/ui/screens/HomeScreen.js +5 -1
  117. package/dist/ui/screens/MapScreen.js +1 -1
  118. package/dist/ui/screens/NowPlayingScreen.js +4 -4
  119. package/dist/ui/screens/SearchScreen.js +3 -1
  120. package/dist/ui/screens/SettingsScreen.js +28 -21
  121. package/dist/ui/screens/StatsScreen.js +3 -1
  122. package/dist/ui/system-actions.js +80 -52
  123. package/dist/ui/terminal-renderer.js +16 -0
  124. package/dist/ui/text-direction.js +9 -0
  125. package/dist/ui/use-alarm-tui.js +57 -42
  126. package/dist/ui/use-app-input.js +84 -30
  127. package/dist/ui/use-command-executor.js +50 -19
  128. package/dist/ui/visualizers/gallop.js +1 -1
  129. package/dist/ui/visualizers/receiver-style-registry.js +2 -1
  130. package/dist/update-check.js +10 -18
  131. package/docs/THIRD_PARTY_NOTICES.md +6 -4
  132. package/package.json +34 -11
  133. package/scripts/build-airplay-native.mjs +22 -0
  134. package/vendor/node-airtunes2/LICENSE +208 -0
  135. package/vendor/node-airtunes2/RADIOCLI_PATCH.md +29 -0
  136. package/vendor/node-airtunes2/README.md +225 -0
  137. package/vendor/node-airtunes2/UPSTREAM.json +50 -0
  138. package/vendor/node-airtunes2/binding.gyp +41 -0
  139. package/vendor/node-airtunes2/lib/ap2_test.js +4 -0
  140. package/vendor/node-airtunes2/lib/atv.js +307 -0
  141. package/vendor/node-airtunes2/lib/atvAuthenticator.js +136 -0
  142. package/vendor/node-airtunes2/lib/audio_out.js +69 -0
  143. package/vendor/node-airtunes2/lib/circular_buffer.js +133 -0
  144. package/vendor/node-airtunes2/lib/config.js +26 -0
  145. package/vendor/node-airtunes2/lib/device_airtunes.js +532 -0
  146. package/vendor/node-airtunes2/lib/devices.js +266 -0
  147. package/vendor/node-airtunes2/lib/ed25519.js +26 -0
  148. package/vendor/node-airtunes2/lib/homekit/credentials.js +86 -0
  149. package/vendor/node-airtunes2/lib/homekit/encryption.js +69 -0
  150. package/vendor/node-airtunes2/lib/homekit/number.js +44 -0
  151. package/vendor/node-airtunes2/lib/homekit/tlv.js +95 -0
  152. package/vendor/node-airtunes2/lib/http.js +189 -0
  153. package/vendor/node-airtunes2/lib/index.d.ts +141 -0
  154. package/vendor/node-airtunes2/lib/index.js +127 -0
  155. package/vendor/node-airtunes2/lib/ntp.js +37 -0
  156. package/vendor/node-airtunes2/lib/num_util.js +21 -0
  157. package/vendor/node-airtunes2/lib/packet_pool.js +43 -0
  158. package/vendor/node-airtunes2/lib/rtsp.js +1807 -0
  159. package/vendor/node-airtunes2/lib/srp.js +158 -0
  160. package/vendor/node-airtunes2/lib/udp_servers.js +214 -0
  161. package/vendor/node-airtunes2/lib/util.js +12 -0
  162. package/vendor/node-airtunes2/package.json +31 -0
  163. package/vendor/node-airtunes2/src/CADebugMacros.h +257 -0
  164. package/vendor/node-airtunes2/src/CAHostTimeBase.cpp +105 -0
  165. package/vendor/node-airtunes2/src/CAHostTimeBase.h +224 -0
  166. package/vendor/node-airtunes2/src/aes_utils.c +864 -0
  167. package/vendor/node-airtunes2/src/aes_utils.h +24 -0
  168. package/vendor/node-airtunes2/src/base64.c +136 -0
  169. package/vendor/node-airtunes2/src/base64.h +42 -0
  170. package/vendor/node-airtunes2/src/bindings.cc +29 -0
  171. package/vendor/node-airtunes2/src/codec.cc +170 -0
  172. package/vendor/node-airtunes2/src/coreaudio.cc +332 -0
@@ -0,0 +1,189 @@
1
+ const net = require('net')
2
+
3
+ // ...
4
+
5
+ const HttpMessage = (parseStartLine, writeStartLine) => {
6
+ const instance = {}
7
+
8
+ instance.parse = (buffer) => {
9
+ const messageObject = {}
10
+
11
+ // ...
12
+
13
+ let bodyIndex = buffer.indexOf('\r\n\r\n')
14
+ let headerString = buffer.slice(0, bodyIndex).toString()
15
+ let body = buffer.slice(bodyIndex + 4)
16
+
17
+ headerString.replace(/\r\n/g, '\n')
18
+
19
+ const lines = headerString.split('\n')
20
+
21
+ bodyIndex += 2
22
+
23
+ // ...
24
+
25
+ let line = lines.shift()
26
+ parseStartLine(line, messageObject)
27
+
28
+ // ...
29
+
30
+ messageObject.headers = {}
31
+
32
+ line = lines.shift()
33
+ while (line) {
34
+ const headerName = line.substr(0, line.indexOf(':'))
35
+ const headerValue = line.substr(line.indexOf(':') + 1)
36
+
37
+ messageObject.headers[headerName] = headerValue.trim()
38
+
39
+ line = lines.shift()
40
+ }
41
+
42
+ // ...
43
+
44
+ if (messageObject.headers['Content-Length'] && messageObject.headers['Content-Length'] != 0) {
45
+ messageObject.body = body
46
+ }
47
+
48
+ return messageObject
49
+ }
50
+
51
+ instance.write = (messageObject) => {
52
+ let messageString = writeStartLine(messageObject)
53
+ messageString += '\r\n'
54
+
55
+ if (messageObject.body) {
56
+ messageObject.headers['Content-Length'] = Buffer.byteLength(messageObject.body)
57
+ }
58
+
59
+ for (const header in messageObject.headers) {
60
+ messageString += `${header}: ${messageObject.headers[header]}\r\n`
61
+ }
62
+
63
+ messageString += '\r\n'
64
+
65
+ const buffer = Buffer.from(messageString)
66
+
67
+ if (!messageObject.body) {
68
+ return buffer
69
+ }
70
+
71
+ return Buffer.concat([buffer, messageObject.body], buffer.length + messageObject.body.length)
72
+ }
73
+
74
+ return instance
75
+ }
76
+
77
+ const HttpRequest
78
+ = () => HttpMessage(
79
+ () => {}, // currently not parsing requests.
80
+ messageObject => `${messageObject.method} ${messageObject.path} HTTP/1.1`,
81
+ )
82
+
83
+ const HttpResponse
84
+ = () => HttpMessage(
85
+ (line, messageObject) => messageObject.statusCode = parseInt(line.split(' ')[1]),
86
+ () => {}, // currently not writing responses.
87
+ )
88
+
89
+ // ...
90
+
91
+ class HttpClient {
92
+ constructor() {
93
+ this.resolveQueue = []
94
+ this.pendingResponse = null
95
+ }
96
+
97
+ // ....
98
+
99
+ parseResponse(data) {
100
+ const res = HttpResponse().parse(data)
101
+ if (res.headers['Content-Length'] > 0) {
102
+ const remaining = res.headers['Content-Length'] - res.body.byteLength
103
+ if (remaining > 0) {
104
+ // not all data for this response's corresponding request was read. Create a pending response object
105
+ // to use for further reads.
106
+ this.pendingResponse = {
107
+ res,
108
+ remaining,
109
+ }
110
+ }
111
+ }
112
+
113
+ if (!this.pendingResponse) {
114
+ const rr = this.resolveQueue.shift()
115
+ res.statusCode === 200
116
+ ? rr.resolve(res)
117
+ : rr.resolve(null)
118
+ }
119
+ }
120
+
121
+ // ...
122
+
123
+ connect(host, port = 80) {
124
+ this.host = host
125
+
126
+ return new Promise((resolve) => {
127
+ this.socket = net.connect(
128
+ {
129
+ host,
130
+ port,
131
+ },
132
+ resolve,
133
+ )
134
+
135
+ this.socket.on('data', (data) => {
136
+ if (!this.pendingResponse) {
137
+ // there is no response pending, parse the data.
138
+ this.parseResponse(data)
139
+ }
140
+ else {
141
+ // incoming data for the pending response.
142
+ this.pendingResponse.res.body = Buffer.concat(
143
+ [this.pendingResponse.res.body, data],
144
+ data.byteLength + this.pendingResponse.res.body.byteLength,
145
+ )
146
+
147
+ this.pendingResponse.remaining -= data.byteLength
148
+ if (this.pendingResponse.remaining === 0) {
149
+ // all remaining data for the pending response has been read; resolve the promise for the
150
+ // corresponding request.
151
+ const rr = this.resolveQueue.shift()
152
+ this.pendingResponse.res.statusCode === 200
153
+ ? rr.resolve(this.pendingResponse.res)
154
+ : rr.reject(new Error(`HTTP status: ${this.pendingResponse.res.statusCode}`))
155
+
156
+ this.pendingResponse = null
157
+ }
158
+ }
159
+ })
160
+ })
161
+ }
162
+
163
+ request(method, path, headers, body) {
164
+ headers = headers || {}
165
+ // headers['Host'] = `${this.host}:${this.socket.remotePort}`;
166
+
167
+ const data = HttpRequest().write({
168
+ method,
169
+ path,
170
+ headers,
171
+ body,
172
+ })
173
+
174
+ // ...
175
+
176
+ return new Promise((resolve, reject) => {
177
+ this.resolveQueue.push({ resolve, reject })
178
+ this.socket.write(data)
179
+ })
180
+ }
181
+
182
+ close() {
183
+ this.socket.end()
184
+ }
185
+ }
186
+
187
+ // ...
188
+
189
+ module.exports = () => new HttpClient()
@@ -0,0 +1,141 @@
1
+ // Path: node_modules/airtunes2/lib/index.d.ts
2
+ declare module 'airtunes2' {
3
+ export = AirTunes.Client;
4
+ }
5
+
6
+ declare namespace AirTunes {
7
+
8
+ /**
9
+ * AirTunes Casting Device
10
+ */
11
+ class CastDevice {
12
+ name: string
13
+ host: string
14
+ port: number
15
+ addresses: string | string[]
16
+ txt: string[]
17
+ airplay2: boolean
18
+ }
19
+
20
+ /**
21
+ * AirTunes Controller
22
+ */
23
+ class Controller {
24
+ key: string
25
+ setPasscode(passcode: string): void
26
+ setVolume(volume: number, cb?: Function): void
27
+ stop(cb?: Function): void
28
+ on(event: 'status', cb: (status: string) => void): void
29
+ }
30
+
31
+ /**
32
+ * AirTunes Device
33
+ * @param port The port of the device as reported by Zeroconf (default: 5000)
34
+ * @param volume The initial volume, which must be between 0 and 100. (default: 50)
35
+ * @param password The password for the device, if required. Bonjour indicates if the device demands a password.
36
+ */
37
+ interface AirPlayDevice {
38
+ port: number
39
+ volume: number
40
+ password?: string
41
+ txt: string
42
+ airplay2: boolean
43
+ debug: boolean
44
+ forceAlac: boolean
45
+ }
46
+
47
+ interface CircularBuffer {
48
+ write(data: Buffer): void
49
+ }
50
+
51
+ /**
52
+ * AirTunes Server
53
+ */
54
+ class Client {
55
+ constructor();
56
+
57
+ /**
58
+ * Add a airtunes device
59
+ * @param host The IP address of the device reported by Zeroconf (ipv4)
60
+ * @param options The options for the device (port, volume, password)
61
+ * @param mode The mode of the device (0 = local, 1 = remote, 2 = dual)
62
+ * @param txt The txt record of the device
63
+ */
64
+ add(host: string, options: AirPlayDevice, mode?: number, txt?: string): Controller;
65
+
66
+ /**
67
+ * Stop all devices
68
+ */
69
+ stopAll(cb: Function): void
70
+
71
+ /**
72
+ * Stop a device
73
+ */
74
+ stop(deviceKey: string, cb?: Function): void
75
+
76
+ /**
77
+ * End the circular buffer
78
+ */
79
+ end(): void
80
+
81
+ /**
82
+ * Set the volume of a device
83
+ * @param deviceKey The key of the device
84
+ * @param volume The volume to set (0-100)
85
+ * @param cb The callback function
86
+ */
87
+ setVolume(deviceKey: string, volume: string, cb?: Function): void
88
+
89
+ /**
90
+ * Set the current playback position of a device
91
+ * @param deviceKey The key of the device
92
+ * @param progress The progress to set (0-1)
93
+ * @param duration The duration of the track
94
+ * @param callback The callback function
95
+ */
96
+ setProgress(deviceKey: string, progress: number, duration: number, callback?: Function): void
97
+
98
+ /**
99
+ * Set the playback state of a device
100
+ * @param deviceKey The key of the device
101
+ * @param name The name of the track
102
+ * @param artist The artist of the track
103
+ * @param album The album of the track
104
+ * @param callback The callback function
105
+ */
106
+ setTrackInfo(deviceKey: string, name: string, artist: string, album: string, callback?: Function): void
107
+
108
+ /**
109
+ * Reset the AirTunes client
110
+ */
111
+ reset(): void
112
+
113
+ /**
114
+ * Set the artwork of a device
115
+ * @param deviceKey The key of the device
116
+ * @param art The artwork to set
117
+ * @param contentType The content type of the artwork
118
+ * @param callback The callback function
119
+ */
120
+ setArtwork(deviceKey: string, art: string | Buffer, contentType: string, callback?: Function): void
121
+
122
+
123
+ /**
124
+ * Set the passcode of a device
125
+ * @param deviceKey The key of the device
126
+ * @param passcode The passcode to set
127
+ */
128
+ setPasscode(deviceKey: string, passcode: string): void
129
+
130
+
131
+ // Untyped methods
132
+ addCoreAudio(options: Object): void
133
+ write(data: string): void
134
+
135
+ // Untyped properties
136
+ circularBuffer: CircularBuffer
137
+ devices: unknown
138
+ writable: boolean
139
+ }
140
+
141
+ }
@@ -0,0 +1,127 @@
1
+ const Stream = require('stream')
2
+ const util = require('util')
3
+ const Devices = require('./devices')
4
+ const config = require('./config')
5
+ const CircularBuffer = require('./circular_buffer')
6
+ const AudioOut = require('./audio_out')
7
+ // const mdns = require("mdns-js");
8
+ // var net = require('net');
9
+ function AirTunes() {
10
+ var self = this
11
+
12
+ Stream.call(this)
13
+
14
+ var audioOut = new AudioOut()
15
+ this.devices = new Devices(audioOut)
16
+
17
+ this.devices.init()
18
+ this.devices.on('status', function (key, status, desc) {
19
+ self.emit('device', key, status, desc)
20
+ })
21
+
22
+ this.circularBuffer = new CircularBuffer(config.packets_in_buffer, config.packet_size)
23
+
24
+ this.circularBuffer.on('status', function (status) {
25
+ self.emit('buffer', status)
26
+ })
27
+
28
+ audioOut.init(this.devices, this.circularBuffer)
29
+
30
+ this.circularBuffer.on('drain', function () {
31
+ self.emit('drain')
32
+ })
33
+
34
+ this.circularBuffer.on('error', function (err) {
35
+ self.emit('error', err)
36
+ })
37
+
38
+ this.writable = true
39
+
40
+ // let x = mdns.tcp("dacp");
41
+ // let txt_record = {
42
+ // Ver: "131075",
43
+ // DbId: "63B5E5C0C201542E",
44
+ // txtvers: "1",
45
+ // OSsi: "0x1F5"
46
+ // };
47
+
48
+ // this.remoteBroadcast= mdns.createAdvertisement(x, 5648, {
49
+ // name: "iTunes_Ctrl_04F8191D99BEC6E9",
50
+ // txt: txt_record,
51
+ // });
52
+ // this.remoteBroadcast.start();
53
+
54
+ // this.remoteserver = net.createServer(function(sock) {
55
+ // // We have a connection - a socket object is assigned to the connection automatically
56
+ // // Add a 'data' event handler to this instance of socket
57
+ // sock.on('data', function(data) {
58
+ // console.log('DATA FROM' + sock.remoteAddress + ': ' + data);
59
+ // // Write the data back to the socket, the client will receive it as data from the server
60
+ // sock.write("HTTP/1.1 204 No Content" + "\r\n" +
61
+ // "DAAP-Server: iTunes/10.6 (Mac OS X)" + "\r\n" +
62
+ // "Content-Type: application/x-dmap-tagged" + "\r\n" +
63
+ // "Content-Length: 0\r\n\r\n"
64
+ // );
65
+ // });
66
+
67
+ // // Add a 'close' event handler to this instance of socket
68
+ // sock.on('close', function(data) {
69
+ // console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
70
+ // });
71
+
72
+ // }).listen(5648);
73
+ }
74
+
75
+ util.inherits(AirTunes, Stream)
76
+
77
+ AirTunes.prototype.add = function (host, options, mode = 0, txt = '') {
78
+ return this.devices.add('airtunes', host, options, mode, txt)
79
+ }
80
+
81
+ AirTunes.prototype.addCoreAudio = function (options) {
82
+ return this.devices.add('coreaudio', null, options)
83
+ }
84
+
85
+ AirTunes.prototype.stopAll = function (cb) {
86
+ this.devices.stopAll(cb)
87
+ }
88
+
89
+ AirTunes.prototype.stop = function (deviceKey) {
90
+ this.devices.stop(deviceKey)
91
+ }
92
+
93
+ AirTunes.prototype.setVolume = function (deviceKey, volume, callback) {
94
+ this.devices.setVolume(deviceKey, volume, callback)
95
+ }
96
+
97
+ AirTunes.prototype.setProgress = function (deviceKey, progress, duration, callback) {
98
+ this.devices.setProgress(deviceKey, progress, duration, callback)
99
+ }
100
+
101
+ AirTunes.prototype.setTrackInfo = function (deviceKey, name, artist, album, callback) {
102
+ this.devices.setTrackInfo(deviceKey, name, artist, album, callback)
103
+ }
104
+
105
+ AirTunes.prototype.reset = function () {
106
+ this.circularBuffer.reset()
107
+ }
108
+
109
+ AirTunes.prototype.setArtwork = function (deviceKey, art, contentType, callback) {
110
+ this.devices.setArtwork(deviceKey, art, contentType, callback)
111
+ }
112
+
113
+ AirTunes.prototype.write = function (data) {
114
+ return this.circularBuffer.write(data)
115
+ }
116
+
117
+ AirTunes.prototype.setPasscode = function (deviceKey, passcode) {
118
+ this.devices.setPasscode(deviceKey, passcode)
119
+ }
120
+
121
+ AirTunes.prototype.end = function () {
122
+ this.circularBuffer.end()
123
+ // this.remoteBroadcast.stop();
124
+ // this.remoteserver.close();
125
+ }
126
+
127
+ module.exports = AirTunes
@@ -0,0 +1,37 @@
1
+ const config = require('./config')
2
+
3
+ function NTP() {
4
+ this.timeRef = new Date().getTime() - config.ntp_epoch * 1000
5
+ }
6
+
7
+ NTP.prototype.timestamp = function () {
8
+ const time = new Date().getTime() - this.timeRef
9
+ const sec = Math.floor(time / 1000)
10
+
11
+ const msec = time - sec * 1000
12
+ const ntp_msec = Math.floor(msec * 4294967.296)
13
+
14
+ const ts = new Buffer(8)
15
+
16
+ ts.writeUInt32BE(sec, 0)
17
+ ts.writeUInt32BE(ntp_msec, 4)
18
+
19
+ return ts
20
+ }
21
+
22
+ NTP.prototype.getTime = function (time) {
23
+ var time = new Date().getTime() - this.timeRef
24
+ var sec = Math.floor(time / 1000)
25
+
26
+ var msec = time - sec * 1000
27
+ var ntp_msec = Math.floor(msec * 4294967.296)
28
+
29
+ var ts = new Buffer(8)
30
+
31
+ ts.writeUInt32BE(sec, 0)
32
+ ts.writeUInt32BE(ntp_msec, 4)
33
+ console.log(time, sec)
34
+ return ntp_msec
35
+ }
36
+
37
+ module.exports = new NTP()
@@ -0,0 +1,21 @@
1
+ const crypto = require('crypto')
2
+
3
+ exports.randomHex = function (n) {
4
+ return crypto.randomBytes(n).toString('hex')
5
+ }
6
+
7
+ exports.randomBase64 = function (n) {
8
+ return crypto.randomBytes(n).toString('base64').replace('=', '')
9
+ }
10
+
11
+ exports.randomInt = function (n) {
12
+ return Math.floor(Math.random() * Math.pow(10, n))
13
+ }
14
+
15
+ exports.low16 = function (i) {
16
+ return Math.abs(i) % 65536
17
+ }
18
+
19
+ exports.low32 = function (i) {
20
+ return Math.abs(i) % 4294967296
21
+ }
@@ -0,0 +1,43 @@
1
+ const config = require('./config')
2
+
3
+ function PacketPool() {
4
+ this.pool = []
5
+ }
6
+
7
+ PacketPool.prototype.getPacket = function () {
8
+ let packet = this.pool.shift()
9
+
10
+ if (!packet) {
11
+ packet = new Packet(this)
12
+ }
13
+ else
14
+ packet.retain()
15
+
16
+ return packet
17
+ }
18
+
19
+ PacketPool.prototype.release = function (packet) {
20
+ this.pool.push(packet)
21
+ }
22
+
23
+ function Packet(pool) {
24
+ this.pool = pool
25
+ this.ref = 1
26
+ this.seq = null
27
+ this.pcm = new Buffer(config.packet_size)
28
+ }
29
+
30
+ Packet.prototype.retain = function () {
31
+ this.ref++
32
+ }
33
+
34
+ Packet.prototype.release = function () {
35
+ this.ref--
36
+
37
+ if (this.ref === 0) {
38
+ this.seq = null
39
+ this.pool.release(this)
40
+ }
41
+ }
42
+
43
+ module.exports = PacketPool