@ciphore/radiocli 0.2.4 → 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 (134) hide show
  1. package/CHANGELOG.md +70 -2
  2. package/CONTRIBUTING.md +10 -0
  3. package/README.md +108 -253
  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 +226 -81
  9. package/dist/agent/launcher.js +2 -1
  10. package/dist/agent/mcp-server.js +10 -5
  11. package/dist/agent/service.js +75 -40
  12. package/dist/agent/session.js +214 -24
  13. package/dist/agent/tui-session.js +213 -0
  14. package/dist/alarms/cli.js +19 -3
  15. package/dist/alarms/occurrence-cache.js +25 -0
  16. package/dist/alarms/runner.js +87 -23
  17. package/dist/alarms/schedule.js +29 -1
  18. package/dist/alarms/scheduler.js +11 -3
  19. package/dist/alarms/system-volume-linux.js +160 -0
  20. package/dist/alarms/system-volume-ownership.js +76 -8
  21. package/dist/alarms/system-volume.js +44 -23
  22. package/dist/cli/arguments.js +212 -0
  23. package/dist/cli/completion.js +44 -0
  24. package/dist/cli/doctor.js +156 -0
  25. package/dist/cli/interactive.js +79 -0
  26. package/dist/cli/listener.js +227 -0
  27. package/dist/cli/output.js +121 -0
  28. package/dist/cli/render-tui.js +34 -0
  29. package/dist/cli.js +178 -199
  30. package/dist/platform/capabilities.js +8 -1
  31. package/dist/platform/desktop-media.js +61 -0
  32. package/dist/platform/diagnostics.js +273 -0
  33. package/dist/platform/json-worker.js +111 -0
  34. package/dist/platform/launch-command.js +9 -6
  35. package/dist/platform/mpris.js +356 -0
  36. package/dist/platform/network.js +69 -1
  37. package/dist/platform/omarchy.js +147 -0
  38. package/dist/platform/packages.js +7 -1
  39. package/dist/platform/runtime.js +1 -1
  40. package/dist/platform/terminals.js +24 -4
  41. package/dist/player/airplay-discovery.js +144 -61
  42. package/dist/player/airplay-policy.js +15 -0
  43. package/dist/player/airplay-process.js +63 -0
  44. package/dist/player/airplay-readiness.js +42 -0
  45. package/dist/player/airplay-sender-health.js +49 -49
  46. package/dist/player/airplay-sender-package.js +5 -0
  47. package/dist/player/airplay-sender-patch.js +102 -4
  48. package/dist/player/airplay-setup.js +51 -0
  49. package/dist/player/airplay-worker.js +97 -41
  50. package/dist/player/backend-install.js +9 -6
  51. package/dist/player/ffmpeg-input.js +37 -0
  52. package/dist/player/mpv-desktop-media.js +194 -0
  53. package/dist/player/mpv-ipc-client.js +51 -2
  54. package/dist/player/player-controller.js +390 -73
  55. package/dist/player/radio-engine.js +282 -0
  56. package/dist/playlists/playlist.js +18 -16
  57. package/dist/providers/cache.js +291 -75
  58. package/dist/providers/discovery-session.js +111 -0
  59. package/dist/providers/provider-manager.js +106 -28
  60. package/dist/providers/radio-browser.js +272 -41
  61. package/dist/providers/radio-garden.js +4 -2
  62. package/dist/setup-playback.js +152 -0
  63. package/dist/setup.js +88 -21
  64. package/dist/storage/file-lock.js +113 -0
  65. package/dist/storage/read-settings.js +33 -0
  66. package/dist/storage/replace-file.js +20 -0
  67. package/dist/storage/repository.js +247 -0
  68. package/dist/storage/station-identity.js +21 -0
  69. package/dist/storage/station-schema.js +27 -0
  70. package/dist/storage/store.js +249 -76
  71. package/dist/ui/AdaptiveContent.js +18 -10
  72. package/dist/ui/App.js +708 -454
  73. package/dist/ui/AppContent.js +5 -5
  74. package/dist/ui/airplay-settings.js +12 -5
  75. package/dist/ui/bidi-ranges.js +45 -0
  76. package/dist/ui/components/AdaptiveMarquee.js +16 -9
  77. package/dist/ui/format.js +37 -4
  78. package/dist/ui/help-content.js +5 -2
  79. package/dist/ui/rtl-output.js +137 -0
  80. package/dist/ui/screen-items.js +10 -4
  81. package/dist/ui/screens/AirPlaySettingsScreen.js +3 -3
  82. package/dist/ui/screens/AlarmsScreen.js +5 -2
  83. package/dist/ui/screens/HelpScreen.js +3 -3
  84. package/dist/ui/screens/SettingsScreen.js +16 -16
  85. package/dist/ui/screens/StatsScreen.js +1 -1
  86. package/dist/ui/text-direction.js +9 -0
  87. package/dist/ui/use-alarm-tui.js +24 -24
  88. package/dist/ui/use-app-input.js +42 -8
  89. package/dist/ui/use-command-executor.js +21 -14
  90. package/dist/ui/visualizers/gallop.js +1 -1
  91. package/dist/ui/visualizers/receiver-style-registry.js +2 -1
  92. package/dist/update-check.js +2 -1
  93. package/docs/THIRD_PARTY_NOTICES.md +6 -4
  94. package/package.json +34 -11
  95. package/scripts/build-airplay-native.mjs +22 -0
  96. package/vendor/node-airtunes2/LICENSE +208 -0
  97. package/vendor/node-airtunes2/RADIOCLI_PATCH.md +29 -0
  98. package/vendor/node-airtunes2/README.md +225 -0
  99. package/vendor/node-airtunes2/UPSTREAM.json +50 -0
  100. package/vendor/node-airtunes2/binding.gyp +41 -0
  101. package/vendor/node-airtunes2/lib/ap2_test.js +4 -0
  102. package/vendor/node-airtunes2/lib/atv.js +307 -0
  103. package/vendor/node-airtunes2/lib/atvAuthenticator.js +136 -0
  104. package/vendor/node-airtunes2/lib/audio_out.js +69 -0
  105. package/vendor/node-airtunes2/lib/circular_buffer.js +133 -0
  106. package/vendor/node-airtunes2/lib/config.js +26 -0
  107. package/vendor/node-airtunes2/lib/device_airtunes.js +532 -0
  108. package/vendor/node-airtunes2/lib/devices.js +266 -0
  109. package/vendor/node-airtunes2/lib/ed25519.js +26 -0
  110. package/vendor/node-airtunes2/lib/homekit/credentials.js +86 -0
  111. package/vendor/node-airtunes2/lib/homekit/encryption.js +69 -0
  112. package/vendor/node-airtunes2/lib/homekit/number.js +44 -0
  113. package/vendor/node-airtunes2/lib/homekit/tlv.js +95 -0
  114. package/vendor/node-airtunes2/lib/http.js +189 -0
  115. package/vendor/node-airtunes2/lib/index.d.ts +141 -0
  116. package/vendor/node-airtunes2/lib/index.js +127 -0
  117. package/vendor/node-airtunes2/lib/ntp.js +37 -0
  118. package/vendor/node-airtunes2/lib/num_util.js +21 -0
  119. package/vendor/node-airtunes2/lib/packet_pool.js +43 -0
  120. package/vendor/node-airtunes2/lib/rtsp.js +1807 -0
  121. package/vendor/node-airtunes2/lib/srp.js +158 -0
  122. package/vendor/node-airtunes2/lib/udp_servers.js +214 -0
  123. package/vendor/node-airtunes2/lib/util.js +12 -0
  124. package/vendor/node-airtunes2/package.json +31 -0
  125. package/vendor/node-airtunes2/src/CADebugMacros.h +257 -0
  126. package/vendor/node-airtunes2/src/CAHostTimeBase.cpp +105 -0
  127. package/vendor/node-airtunes2/src/CAHostTimeBase.h +224 -0
  128. package/vendor/node-airtunes2/src/aes_utils.c +864 -0
  129. package/vendor/node-airtunes2/src/aes_utils.h +24 -0
  130. package/vendor/node-airtunes2/src/base64.c +136 -0
  131. package/vendor/node-airtunes2/src/base64.h +42 -0
  132. package/vendor/node-airtunes2/src/bindings.cc +29 -0
  133. package/vendor/node-airtunes2/src/codec.cc +170 -0
  134. package/vendor/node-airtunes2/src/coreaudio.cc +332 -0
@@ -0,0 +1,332 @@
1
+ // Conversion to modern node (v4)
2
+ //
3
+ // TODO: understand. I have no idea what I'm doing here. HandleScope/Isolate?
4
+ //
5
+ // https://nodejs.org/api/addons.html
6
+ // https://developers.google.com/v8/embed?hl=en
7
+ // https://strongloop.com/strongblog/node-js-v0-12-c-apis-breaking/
8
+ // https://github.com/nodejs/nan/blob/master/doc/persistent.md
9
+
10
+
11
+ #include <node.h>
12
+ #include <node_buffer.h>
13
+ #include <v8.h>
14
+ //Includes from phoenixLib iOS HAL
15
+ #include <stdio.h>
16
+ #include <time.h>
17
+ #include <stdlib.h>
18
+ #include <unistd.h>
19
+ #include <stdarg.h>
20
+ #include <AudioToolbox/AudioToolbox.h>
21
+ #include <CoreFoundation/CoreFoundation.h>
22
+ #include "CAHostTimeBase.h"
23
+ #include <pthread.h>
24
+ #include <sys/resource.h>
25
+
26
+ #define FRAME_SIZE 1408
27
+ #define NUMBER_OF_BUFFERS 100
28
+ #define BUFFER_SIZE FRAME_SIZE * 4
29
+
30
+ using namespace v8;
31
+ using namespace node;
32
+
33
+ namespace nodeairtunes {
34
+
35
+ struct coreAudioObjects {
36
+ AudioQueueRef audioQueue;
37
+
38
+ unsigned int fillBufferIndex; // the index of the audioQueueBuffer that is being filled
39
+
40
+ size_t bytesFilled; // how many bytes have been filled
41
+
42
+ AudioQueueBufferRef audioQueueBuffer[NUMBER_OF_BUFFERS]; // audio queue buffers
43
+ bool inuse[NUMBER_OF_BUFFERS]; // flags to indicate that a buffer is still in use
44
+
45
+ bool isPlaying;
46
+ unsigned int buffersUsed;
47
+
48
+ OSStatus err;
49
+
50
+ pthread_mutex_t queueBuffersMutex; // a mutex to protect the inuse flags
51
+ pthread_cond_t queueBufferReadyCondition; // a condition varable for handling the inuse flags
52
+
53
+ };
54
+
55
+ // This will free the AudioQueue when the wraping JS object is released by the GC
56
+ void coreAudio_weak_callback(const v8::WeakCallbackInfo<coreAudioObjects> &data) {
57
+ struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) data.GetParameter();
58
+ AudioQueueDispose(coreAudio->audioQueue, true);
59
+ }
60
+
61
+ void OnAudioQueueBufferConsumed(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
62
+ struct coreAudioObjects* coreAudio;
63
+ coreAudio = (struct coreAudioObjects*) inUserData;
64
+
65
+ int bufIndex = -1;
66
+ for (unsigned int i = 0; i < NUMBER_OF_BUFFERS; i++) {
67
+ if (inBuffer == coreAudio->audioQueueBuffer[i]) {
68
+ bufIndex = i;
69
+ break;
70
+ }
71
+ }
72
+
73
+ if (bufIndex == -1) {
74
+ pthread_mutex_lock(&(coreAudio->queueBuffersMutex));
75
+ pthread_cond_signal(&(coreAudio->queueBufferReadyCondition));
76
+ pthread_mutex_unlock(&(coreAudio->queueBuffersMutex));
77
+ //DEBUG_AUDIOMANAGER_ERROR("Buffer mismatch !");
78
+ return;
79
+ }
80
+ // signal waiting thread that the buffer is free.
81
+ pthread_mutex_lock(&(coreAudio->queueBuffersMutex));
82
+ coreAudio->inuse[bufIndex] = false;
83
+ coreAudio->buffersUsed--;
84
+ pthread_cond_signal(&(coreAudio->queueBufferReadyCondition));
85
+ pthread_mutex_unlock(&(coreAudio->queueBuffersMutex));
86
+ }
87
+
88
+ static void enqueueBuffer(struct coreAudioObjects *coreAudio) {
89
+
90
+ OSStatus err = 0;
91
+
92
+ // enqueue buffer
93
+ pthread_mutex_lock(&(coreAudio->queueBuffersMutex));
94
+
95
+ AudioQueueBufferRef fillBuf = coreAudio->audioQueueBuffer[coreAudio->fillBufferIndex];
96
+ fillBuf->mAudioDataByteSize = coreAudio->bytesFilled;
97
+ err = AudioQueueEnqueueBuffer(coreAudio->audioQueue, fillBuf, 0, NULL);
98
+ if (err) {
99
+ //DEBUG_AUDIOMANAGER_ERROR("enqueue failed !!!!! %d", coreAudio->fillBufferIndex);
100
+ coreAudio->bytesFilled = 0;
101
+ pthread_mutex_unlock(&(coreAudio->queueBuffersMutex));
102
+ return;
103
+ }
104
+
105
+ coreAudio->inuse[coreAudio->fillBufferIndex] = true; // set in use flag
106
+ coreAudio->buffersUsed++;
107
+
108
+ // go to next buffer
109
+ if (++(coreAudio->fillBufferIndex) >= NUMBER_OF_BUFFERS) coreAudio->fillBufferIndex = 0;
110
+
111
+ coreAudio->bytesFilled = 0; // reset bytes filled
112
+
113
+ // wait until next buffer is not in use
114
+ while (coreAudio->inuse[coreAudio->fillBufferIndex]) {
115
+ pthread_cond_wait(&(coreAudio->queueBufferReadyCondition), &(coreAudio->queueBuffersMutex));
116
+ }
117
+
118
+ pthread_mutex_unlock(&(coreAudio->queueBuffersMutex));
119
+ }
120
+
121
+ void NewCoreAudio(const v8::FunctionCallbackInfo<v8::Value>& args) {
122
+ v8::Isolate* isolate = args.GetIsolate();
123
+
124
+ v8::HandleScope handle_scope(isolate);
125
+
126
+ struct coreAudioObjects *coreAudio
127
+ = (struct coreAudioObjects *) malloc(sizeof (*coreAudio));
128
+
129
+ v8::Persistent<v8::Object> o;
130
+ o.SetWeak(
131
+ coreAudio,
132
+ coreAudio_weak_callback,
133
+ v8::WeakCallbackType::kParameter
134
+ );
135
+
136
+ coreAudio->isPlaying = false;
137
+ coreAudio->buffersUsed = 0;
138
+ coreAudio->bytesFilled = 0;
139
+ coreAudio->fillBufferIndex = 0;
140
+ // initialize a mutex and condition so that we can block on buffers in use.
141
+ pthread_mutex_init(&(coreAudio->queueBuffersMutex), NULL);
142
+ pthread_cond_init(&(coreAudio->queueBufferReadyCondition), NULL);
143
+
144
+ AudioStreamBasicDescription LFormat;
145
+ OSStatus LRet;
146
+
147
+ LFormat.mSampleRate = 44100;
148
+ LFormat.mFormatID = kAudioFormatLinearPCM;
149
+ LFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger; // signed int
150
+ LFormat.mFramesPerPacket = 1; // for uncompressed audio
151
+ LFormat.mBytesPerFrame = 4; //AChannels * 2; // interleaved pcm datas (16bits per chan)
152
+ LFormat.mBytesPerPacket = 4; // for pcm: a packet contains a single frame
153
+ LFormat.mChannelsPerFrame = 2;
154
+ LFormat.mBitsPerChannel = 16;
155
+
156
+ // Allocating AudioQueue
157
+
158
+ if ((LRet = AudioQueueNewOutput(&LFormat, OnAudioQueueBufferConsumed, coreAudio, NULL, NULL, 0, &(coreAudio->audioQueue)))) {
159
+ args.GetReturnValue().Set(v8::Null(isolate));
160
+ return;
161
+ }
162
+
163
+ OSStatus status = 0;
164
+
165
+ // Allocate buffers for the AudioQueue
166
+ for (int i = 0; i < NUMBER_OF_BUFFERS; ++i) {
167
+ status = AudioQueueAllocateBuffer(coreAudio->audioQueue, BUFFER_SIZE, &(coreAudio->audioQueueBuffer[i]));
168
+ coreAudio->inuse[i] = false;
169
+ }
170
+
171
+ args.GetReturnValue().Set(o.Get(isolate));
172
+ }
173
+
174
+ void EnqueuePacket(const v8::FunctionCallbackInfo<v8::Value>& args) {
175
+ v8::Isolate* isolate = args.GetIsolate();
176
+ Local<Context> ctx = isolate->GetCurrentContext();
177
+
178
+ if (args.Length() < 3) {
179
+ printf("expected: EnqueuePacket(coreAudio, pcmData, pcmSize)\n");
180
+ args.GetReturnValue().Set(v8::Null(isolate));
181
+ return;
182
+ }
183
+
184
+ v8::Local<v8::Object> wrapper;
185
+ args[0]->ToObject(ctx).ToLocal(&wrapper);
186
+ struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
187
+
188
+ v8::Local<v8::Value> pcmBuffer = args[1];
189
+ Local<Object> pcmObject;
190
+ pcmBuffer->ToObject(ctx).ToLocal(&pcmObject);
191
+ unsigned char* pcmData = (unsigned char*) (Buffer::Data(pcmObject));
192
+
193
+ int32_t pcmSize = args[2]->Int32Value(ctx).FromJust();
194
+
195
+ //We have all infos needed
196
+
197
+ size_t offset = 0;
198
+ while (pcmSize) {
199
+ // if the space remaining in the buffer is not enough for this packet, then enqueue the buffer.
200
+ size_t bufSpaceRemaining = BUFFER_SIZE - coreAudio->bytesFilled;
201
+ if (bufSpaceRemaining < pcmSize) {
202
+ //DEBUG_AUDIOMANAGER_VERBOSE("Before enqueue");
203
+ enqueueBuffer(coreAudio);
204
+ //DEBUG_AUDIOMANAGER_VERBOSE("After enqueue");
205
+ }
206
+
207
+ bufSpaceRemaining = BUFFER_SIZE - coreAudio->bytesFilled;
208
+ size_t copySize;
209
+ if (bufSpaceRemaining < pcmSize) {
210
+ copySize = bufSpaceRemaining;
211
+ } else {
212
+ copySize = pcmSize;
213
+ }
214
+
215
+ // copy data to the audio queue buffer
216
+ AudioQueueBufferRef fillBuf = coreAudio->audioQueueBuffer[coreAudio->fillBufferIndex];
217
+ memcpy((char*) fillBuf->mAudioData + coreAudio->bytesFilled, (const char*) (pcmData + offset), copySize);
218
+
219
+ // keep track of bytes filled and packets filled
220
+ coreAudio->bytesFilled += copySize;
221
+
222
+ pcmSize -= copySize;
223
+ offset += copySize;
224
+ }
225
+
226
+ args.GetReturnValue().Set(v8::Null(isolate));
227
+ }
228
+
229
+ void Play(const v8::FunctionCallbackInfo<v8::Value>& args) {
230
+ v8::Isolate* isolate = args.GetIsolate();
231
+ Local<Context> ctx = isolate->GetCurrentContext();
232
+
233
+ if (args.Length() < 2) {
234
+ printf("expected: Play(coreAudio, audioQueueTimeRef)\n");
235
+ args.GetReturnValue().Set(v8::Null(isolate));
236
+ return;
237
+ }
238
+
239
+ v8::Local<v8::Object> wrapper;
240
+ args[0]->ToObject(ctx).ToLocal(&wrapper);
241
+ struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
242
+
243
+ int64_t timeStamp = args[1]->IntegerValue(ctx).FromJust();
244
+
245
+ AudioTimeStamp myAudioQueueStartTime; // = {0};
246
+ Float64 theNumberOfSecondsInTheFuture = timeStamp/44100.0;
247
+
248
+ Float64 hostTimeFreq = CAHostTimeBase::GetFrequency();
249
+ UInt64 startHostTime = CAHostTimeBase::GetCurrentTime() + theNumberOfSecondsInTheFuture * hostTimeFreq;
250
+
251
+ myAudioQueueStartTime.mFlags = kAudioTimeStampHostTimeValid;
252
+ myAudioQueueStartTime.mHostTime = startHostTime;
253
+
254
+ if (coreAudio->isPlaying == false) {
255
+ if (AudioQueueStart(coreAudio->audioQueue, &myAudioQueueStartTime)) {
256
+ printf("AudioQueueStart() Failed!\n");
257
+ } else {
258
+ coreAudio->isPlaying = true;
259
+ }
260
+ }
261
+
262
+ args.GetReturnValue().Set(v8::Null(isolate));
263
+ }
264
+
265
+ void Stop(const v8::FunctionCallbackInfo<v8::Value>& args) {
266
+ v8::Isolate* isolate = args.GetIsolate();
267
+ Local<Context> ctx = isolate->GetCurrentContext();
268
+
269
+ if (args.Length() < 1) {
270
+ printf("expected: Play(coreAudio)\n");
271
+ args.GetReturnValue().Set(v8::Null(isolate));
272
+ return;
273
+ }
274
+
275
+ v8::Local<v8::Object> wrapper;
276
+ args[0]->ToObject(ctx).ToLocal(&wrapper);
277
+ struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
278
+
279
+ if (coreAudio->isPlaying) {
280
+ if (AudioQueueStop(coreAudio->audioQueue, true)) {
281
+ printf("AudioQueueStop() Failed!\n");
282
+ } else {
283
+ coreAudio->isPlaying = false;
284
+ }
285
+ }
286
+
287
+ args.GetReturnValue().Set(v8::Null(isolate));
288
+ }
289
+
290
+ void SetVolume(const v8::FunctionCallbackInfo<v8::Value>& args) {
291
+ v8::Isolate* isolate = args.GetIsolate();
292
+ Local<Context> ctx = isolate->GetCurrentContext();
293
+
294
+ if (args.Length() < 1) {
295
+ printf("expected: Play(coreAudio)\n");
296
+ args.GetReturnValue().Set(v8::Null(isolate));
297
+ return;
298
+ }
299
+
300
+ v8::Local<v8::Object> wrapper;
301
+ args[0]->ToObject(ctx).ToLocal(&wrapper);
302
+ struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
303
+ float volumeToSet=args[1]->IntegerValue(ctx).FromJust()/100.0;
304
+
305
+ if (coreAudio->isPlaying)
306
+ AudioQueueSetParameter(coreAudio->audioQueue, kAudioQueueParam_Volume, volumeToSet);
307
+
308
+ args.GetReturnValue().Set(v8::Null(isolate));
309
+ }
310
+
311
+ void GetBufferLevel(const v8::FunctionCallbackInfo<v8::Value>& args) {
312
+ v8::Isolate* isolate = args.GetIsolate();
313
+ Local<Context> ctx = isolate->GetCurrentContext();
314
+
315
+ v8::Local<v8::Object> wrapper;
316
+ args[0]->ToObject(ctx).ToLocal(&wrapper);
317
+ struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
318
+ v8::Local<v8::Integer> o = v8::Integer::New(isolate, (int)((coreAudio->buffersUsed/(float)NUMBER_OF_BUFFERS)*100));
319
+
320
+ args.GetReturnValue().Set(o);
321
+ }
322
+
323
+ void InitCoreAudio(v8::Local<v8::Object> target) {
324
+ NODE_SET_METHOD(target, "enqueuePacket", EnqueuePacket);
325
+ NODE_SET_METHOD(target, "newCoreAudio", NewCoreAudio);
326
+ NODE_SET_METHOD(target, "play", Play);
327
+ NODE_SET_METHOD(target, "stop", Stop);
328
+ NODE_SET_METHOD(target, "setVolume", SetVolume);
329
+ NODE_SET_METHOD(target, "getBufferLevel", GetBufferLevel);
330
+ }
331
+
332
+ }