@jtarrio/webrtlsdr 0.0.1

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 (119) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +69 -0
  3. package/dist/audio/player.d.ts +24 -0
  4. package/dist/audio/player.d.ts.map +1 -0
  5. package/dist/audio/player.js +68 -0
  6. package/dist/audio/player.js.map +1 -0
  7. package/dist/demod/demodulator.d.ts +59 -0
  8. package/dist/demod/demodulator.d.ts.map +1 -0
  9. package/dist/demod/demodulator.js +150 -0
  10. package/dist/demod/demodulator.js.map +1 -0
  11. package/dist/demod/sample-counter.d.ts +18 -0
  12. package/dist/demod/sample-counter.d.ts.map +1 -0
  13. package/dist/demod/sample-counter.js +43 -0
  14. package/dist/demod/sample-counter.js.map +1 -0
  15. package/dist/demod/scheme-am.d.ts +32 -0
  16. package/dist/demod/scheme-am.d.ts.map +1 -0
  17. package/dist/demod/scheme-am.js +75 -0
  18. package/dist/demod/scheme-am.js.map +1 -0
  19. package/dist/demod/scheme-cw.d.ts +22 -0
  20. package/dist/demod/scheme-cw.d.ts.map +1 -0
  21. package/dist/demod/scheme-cw.js +68 -0
  22. package/dist/demod/scheme-cw.js.map +1 -0
  23. package/dist/demod/scheme-nbfm.d.ts +32 -0
  24. package/dist/demod/scheme-nbfm.d.ts.map +1 -0
  25. package/dist/demod/scheme-nbfm.js +76 -0
  26. package/dist/demod/scheme-nbfm.js.map +1 -0
  27. package/dist/demod/scheme-ssb.d.ts +33 -0
  28. package/dist/demod/scheme-ssb.d.ts.map +1 -0
  29. package/dist/demod/scheme-ssb.js +75 -0
  30. package/dist/demod/scheme-ssb.js.map +1 -0
  31. package/dist/demod/scheme-wbfm.d.ts +38 -0
  32. package/dist/demod/scheme-wbfm.d.ts.map +1 -0
  33. package/dist/demod/scheme-wbfm.js +106 -0
  34. package/dist/demod/scheme-wbfm.js.map +1 -0
  35. package/dist/demod/scheme.d.ts +78 -0
  36. package/dist/demod/scheme.d.ts.map +1 -0
  37. package/dist/demod/scheme.js +96 -0
  38. package/dist/demod/scheme.js.map +1 -0
  39. package/dist/demod/spectrum.d.ts +18 -0
  40. package/dist/demod/spectrum.d.ts.map +1 -0
  41. package/dist/demod/spectrum.js +76 -0
  42. package/dist/demod/spectrum.js.map +1 -0
  43. package/dist/dsp/buffers.d.ts +72 -0
  44. package/dist/dsp/buffers.d.ts.map +1 -0
  45. package/dist/dsp/buffers.js +109 -0
  46. package/dist/dsp/buffers.js.map +1 -0
  47. package/dist/dsp/coefficients.d.ts +22 -0
  48. package/dist/dsp/coefficients.d.ts.map +1 -0
  49. package/dist/dsp/coefficients.js +77 -0
  50. package/dist/dsp/coefficients.js.map +1 -0
  51. package/dist/dsp/converters.d.ts +15 -0
  52. package/dist/dsp/converters.d.ts.map +1 -0
  53. package/dist/dsp/converters.js +43 -0
  54. package/dist/dsp/converters.js.map +1 -0
  55. package/dist/dsp/demodulators.d.ts +72 -0
  56. package/dist/dsp/demodulators.d.ts.map +1 -0
  57. package/dist/dsp/demodulators.js +245 -0
  58. package/dist/dsp/demodulators.js.map +1 -0
  59. package/dist/dsp/fft.d.ts +53 -0
  60. package/dist/dsp/fft.d.ts.map +1 -0
  61. package/dist/dsp/fft.js +175 -0
  62. package/dist/dsp/fft.js.map +1 -0
  63. package/dist/dsp/filters.d.ts +91 -0
  64. package/dist/dsp/filters.d.ts.map +1 -0
  65. package/dist/dsp/filters.js +250 -0
  66. package/dist/dsp/filters.js.map +1 -0
  67. package/dist/dsp/power.d.ts +2 -0
  68. package/dist/dsp/power.d.ts.map +1 -0
  69. package/dist/dsp/power.js +10 -0
  70. package/dist/dsp/power.js.map +1 -0
  71. package/dist/dsp/resamplers.d.ts +33 -0
  72. package/dist/dsp/resamplers.d.ts.map +1 -0
  73. package/dist/dsp/resamplers.js +91 -0
  74. package/dist/dsp/resamplers.js.map +1 -0
  75. package/dist/errors.d.ts +19 -0
  76. package/dist/errors.d.ts.map +1 -0
  77. package/dist/errors.js +37 -0
  78. package/dist/errors.js.map +1 -0
  79. package/dist/radio/msgqueue.d.ts +23 -0
  80. package/dist/radio/msgqueue.d.ts.map +1 -0
  81. package/dist/radio/msgqueue.js +52 -0
  82. package/dist/radio/msgqueue.js.map +1 -0
  83. package/dist/radio/radio.d.ts +81 -0
  84. package/dist/radio/radio.d.ts.map +1 -0
  85. package/dist/radio/radio.js +305 -0
  86. package/dist/radio/radio.js.map +1 -0
  87. package/dist/radio/sample_receiver.d.ts +11 -0
  88. package/dist/radio/sample_receiver.d.ts.map +1 -0
  89. package/dist/radio/sample_receiver.js +49 -0
  90. package/dist/radio/sample_receiver.js.map +1 -0
  91. package/dist/rtlsdr/r820t.d.ts +18 -0
  92. package/dist/rtlsdr/r820t.d.ts.map +1 -0
  93. package/dist/rtlsdr/r820t.js +39 -0
  94. package/dist/rtlsdr/r820t.js.map +1 -0
  95. package/dist/rtlsdr/r828d.d.ts +28 -0
  96. package/dist/rtlsdr/r828d.d.ts.map +1 -0
  97. package/dist/rtlsdr/r828d.js +120 -0
  98. package/dist/rtlsdr/r828d.js.map +1 -0
  99. package/dist/rtlsdr/r8xx.d.ts +90 -0
  100. package/dist/rtlsdr/r8xx.d.ts.map +1 -0
  101. package/dist/rtlsdr/r8xx.js +468 -0
  102. package/dist/rtlsdr/r8xx.js.map +1 -0
  103. package/dist/rtlsdr/rtl2832u.d.ts +74 -0
  104. package/dist/rtlsdr/rtl2832u.d.ts.map +1 -0
  105. package/dist/rtlsdr/rtl2832u.js +342 -0
  106. package/dist/rtlsdr/rtl2832u.js.map +1 -0
  107. package/dist/rtlsdr/rtlcom.d.ts +144 -0
  108. package/dist/rtlsdr/rtlcom.d.ts.map +1 -0
  109. package/dist/rtlsdr/rtlcom.js +299 -0
  110. package/dist/rtlsdr/rtlcom.js.map +1 -0
  111. package/dist/rtlsdr/rtldevice.d.ts +53 -0
  112. package/dist/rtlsdr/rtldevice.d.ts.map +1 -0
  113. package/dist/rtlsdr/rtldevice.js +24 -0
  114. package/dist/rtlsdr/rtldevice.js.map +1 -0
  115. package/dist/rtlsdr/tuner.d.ts +20 -0
  116. package/dist/rtlsdr/tuner.d.ts.map +1 -0
  117. package/dist/rtlsdr/tuner.js +15 -0
  118. package/dist/rtlsdr/tuner.js.map +1 -0
  119. package/package.json +20 -0
@@ -0,0 +1,91 @@
1
+ // Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
2
+ // Copyright 2013 Google Inc. All rights reserved.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ import { Float32Buffer } from "./buffers";
16
+ import { makeLowPassKernel } from "./coefficients";
17
+ import { FIRFilter } from "./filters";
18
+ /** A class to convert the input to a lower sample rate. */
19
+ class Downsampler {
20
+ ratio;
21
+ /**
22
+ * @param ratio The ratio of input/output sample rates.
23
+ * @param kernel The coefficients for the low-pass filter.
24
+ */
25
+ constructor(ratio, kernel) {
26
+ this.ratio = ratio;
27
+ this.filter = new FIRFilter(kernel);
28
+ this.buffer = new Float32Buffer(2);
29
+ }
30
+ filter;
31
+ buffer;
32
+ /**
33
+ * Returns a downsampled version of the given samples.
34
+ * @param samples The sample block to downsample.
35
+ * @returns The downsampled block.
36
+ */
37
+ downsample(samples) {
38
+ const ratio = this.ratio;
39
+ const len = Math.floor(samples.length / ratio);
40
+ let output = this.buffer.get(len);
41
+ this.filter.loadSamples(samples);
42
+ for (let i = 0; i < len; ++i) {
43
+ output[i] = this.filter.get(Math.floor(i * ratio));
44
+ }
45
+ return output;
46
+ }
47
+ }
48
+ /** A class to convert a real input to a lower sample rate. */
49
+ export class RealDownsampler {
50
+ /**
51
+ * @param inRate The input sample rate.
52
+ * @param outRate The output sample rate.
53
+ * @param filterLen The size of the low-pass filter.
54
+ */
55
+ constructor(inRate, outRate, filterLen) {
56
+ const kernel = makeLowPassKernel(inRate, outRate / 2, filterLen);
57
+ this.downsampler = new Downsampler(inRate / outRate, kernel);
58
+ }
59
+ downsampler;
60
+ /**
61
+ * @param input The signal in the original sample rate.
62
+ * @returns The resampled signal.
63
+ */
64
+ downsample(input) {
65
+ return this.downsampler.downsample(input);
66
+ }
67
+ }
68
+ /** A class to convert a complex input to a lower sample rate. */
69
+ export class ComplexDownsampler {
70
+ /**
71
+ * @param inRate The input sample rate.
72
+ * @param outRate The output sample rate.
73
+ * @param filterLen The size of the low-pass filter.
74
+ */
75
+ constructor(inRate, outRate, filterLen) {
76
+ const kernel = makeLowPassKernel(inRate, outRate / 2, filterLen);
77
+ this.downsamplerI = new Downsampler(inRate / outRate, kernel);
78
+ this.downsamplerQ = new Downsampler(inRate / outRate, kernel);
79
+ }
80
+ downsamplerI;
81
+ downsamplerQ;
82
+ /**
83
+ * @param I The signal's real component.
84
+ * @param Q The signal's imaginary component.
85
+ * @returns An array with the output's real and imaginary components.
86
+ */
87
+ downsample(I, Q) {
88
+ return [this.downsamplerI.downsample(I), this.downsamplerQ.downsample(Q)];
89
+ }
90
+ }
91
+ //# sourceMappingURL=resamplers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resamplers.js","sourceRoot":"","sources":["../../src/dsp/resamplers.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,kDAAkD;AAClD,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,2DAA2D;AAC3D,MAAM,WAAW;IAML;IALV;;;OAGG;IACH,YACU,KAAa,EACrB,MAAoB;QADZ,UAAK,GAAL,KAAK,CAAQ;QAGrB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAEO,MAAM,CAAY;IAClB,MAAM,CAAgB;IAE9B;;;;OAIG;IACH,UAAU,CAAC,OAAqB;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QAC/C,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,OAAO,eAAe;IAC1B;;;;OAIG;IACH,YAAY,MAAc,EAAE,OAAe,EAAE,SAAiB;QAC5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;QACjE,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/D,CAAC;IAEO,WAAW,CAAc;IAEjC;;;OAGG;IACH,UAAU,CAAC,KAAmB;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;CACF;AAED,iEAAiE;AACjE,MAAM,OAAO,kBAAkB;IAC7B;;;;OAIG;IACH,YAAY,MAAc,EAAE,OAAe,EAAE,SAAiB;QAC5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;QACjE,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAEO,YAAY,CAAc;IAC1B,YAAY,CAAc;IAElC;;;;OAIG;IACH,UAAU,CAAC,CAAe,EAAE,CAAe;QACzC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ export declare class RadioError extends Error {
2
+ constructor(message: string, type?: RadioErrorType, options?: RadioErrorOptions);
3
+ constructor(message: string, type?: RadioErrorType);
4
+ constructor(message: string, options?: RadioErrorOptions);
5
+ type?: RadioErrorType;
6
+ }
7
+ export declare enum RadioErrorType {
8
+ NoUsbSupport = 0,
9
+ NoDeviceSelected = 1,
10
+ UnsupportedDevice = 2,
11
+ UsbTransferError = 3,
12
+ TunerError = 4,
13
+ DemodulationError = 5
14
+ }
15
+ type RadioErrorOptions = {
16
+ cause?: any;
17
+ };
18
+ export {};
19
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAcA,qBAAa,UAAW,SAAQ,KAAK;gBAEjC,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,iBAAiB;gBAEjB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc;gBACtC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB;IAoBxD,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,oBAAY,cAAc;IACxB,YAAY,IAAA;IACZ,gBAAgB,IAAA;IAChB,iBAAiB,IAAA;IACjB,gBAAgB,IAAA;IAChB,UAAU,IAAA;IACV,iBAAiB,IAAA;CAClB;AAED,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,37 @@
1
+ // Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ export class RadioError extends Error {
15
+ constructor(message, typeOrOptions, options) {
16
+ super(message, options !== undefined
17
+ ? options
18
+ : typeof typeOrOptions === "object"
19
+ ? typeOrOptions
20
+ : undefined);
21
+ if (typeof typeOrOptions === "number") {
22
+ this.type = typeOrOptions;
23
+ this.name = `RadioError.${RadioErrorType[typeOrOptions]}`;
24
+ }
25
+ }
26
+ type;
27
+ }
28
+ export var RadioErrorType;
29
+ (function (RadioErrorType) {
30
+ RadioErrorType[RadioErrorType["NoUsbSupport"] = 0] = "NoUsbSupport";
31
+ RadioErrorType[RadioErrorType["NoDeviceSelected"] = 1] = "NoDeviceSelected";
32
+ RadioErrorType[RadioErrorType["UnsupportedDevice"] = 2] = "UnsupportedDevice";
33
+ RadioErrorType[RadioErrorType["UsbTransferError"] = 3] = "UsbTransferError";
34
+ RadioErrorType[RadioErrorType["TunerError"] = 4] = "TunerError";
35
+ RadioErrorType[RadioErrorType["DemodulationError"] = 5] = "DemodulationError";
36
+ })(RadioErrorType || (RadioErrorType = {}));
37
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,MAAM,OAAO,UAAW,SAAQ,KAAK;IAQnC,YACE,OAAe,EACf,aAAkD,EAClD,OAA2B;QAE3B,KAAK,CACH,OAAO,EACP,OAAO,KAAK,SAAS;YACnB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,OAAO,aAAa,KAAK,QAAQ;gBACjC,CAAC,CAAC,aAAa;gBACf,CAAC,CAAC,SAAS,CAChB,CAAC;QACF,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;YAC1B,IAAI,CAAC,IAAI,GAAG,cAAc,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,IAAI,CAAkB;CACvB;AAED,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACxB,mEAAY,CAAA;IACZ,2EAAgB,CAAA;IAChB,6EAAiB,CAAA;IACjB,2EAAgB,CAAA;IAChB,+DAAU,CAAA;IACV,6EAAiB,CAAA;AACnB,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB"}
@@ -0,0 +1,23 @@
1
+ /** A message channel, in which messages are sent and received asynchronously. */
2
+ export declare class Channel<Msg> {
3
+ constructor();
4
+ /** Messages waiting to be delivered. */
5
+ private msgQueue;
6
+ /** Clients waiting to receive messages. */
7
+ private notifyQueue;
8
+ /**
9
+ * Sends a message.
10
+ *
11
+ * If there is a client waiting to receive a message, it is delivered straight to it.
12
+ * Otherwise, the message is added to the queue.
13
+ */
14
+ send(msg: Msg): void;
15
+ /**
16
+ * Receives a message, returning a promise.
17
+ *
18
+ * If there is a message in the queue, the promise resolves to that message.
19
+ * Otherwise, the promise will resolve when a message is received.
20
+ */
21
+ receive(): Promise<Msg>;
22
+ }
23
+ //# sourceMappingURL=msgqueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msgqueue.d.ts","sourceRoot":"","sources":["../../src/radio/msgqueue.ts"],"names":[],"mappings":"AAcA,iFAAiF;AACjF,qBAAa,OAAO,CAAC,GAAG;;IAMtB,wCAAwC;IACxC,OAAO,CAAC,QAAQ,CAAQ;IACxB,2CAA2C;IAC3C,OAAO,CAAC,WAAW,CAAyB;IAE5C;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG;IASb;;;;;OAKG;IACH,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC;CAKxB"}
@@ -0,0 +1,52 @@
1
+ // Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ /** A message channel, in which messages are sent and received asynchronously. */
15
+ export class Channel {
16
+ constructor() {
17
+ this.msgQueue = [];
18
+ this.notifyQueue = [];
19
+ }
20
+ /** Messages waiting to be delivered. */
21
+ msgQueue;
22
+ /** Clients waiting to receive messages. */
23
+ notifyQueue;
24
+ /**
25
+ * Sends a message.
26
+ *
27
+ * If there is a client waiting to receive a message, it is delivered straight to it.
28
+ * Otherwise, the message is added to the queue.
29
+ */
30
+ send(msg) {
31
+ let notif = this.notifyQueue.shift();
32
+ if (notif !== undefined) {
33
+ notif(msg);
34
+ }
35
+ else {
36
+ this.msgQueue.push(msg);
37
+ }
38
+ }
39
+ /**
40
+ * Receives a message, returning a promise.
41
+ *
42
+ * If there is a message in the queue, the promise resolves to that message.
43
+ * Otherwise, the promise will resolve when a message is received.
44
+ */
45
+ receive() {
46
+ let msg = this.msgQueue.shift();
47
+ if (msg !== undefined)
48
+ return Promise.resolve(msg);
49
+ return new Promise((r) => this.notifyQueue.push(r));
50
+ }
51
+ }
52
+ //# sourceMappingURL=msgqueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msgqueue.js","sourceRoot":"","sources":["../../src/radio/msgqueue.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,iFAAiF;AACjF,MAAM,OAAO,OAAO;IAClB;QACE,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;IACxB,CAAC;IAED,wCAAwC;IAChC,QAAQ,CAAQ;IACxB,2CAA2C;IACnC,WAAW,CAAyB;IAE5C;;;;;OAKG;IACH,IAAI,CAAC,GAAQ;QACX,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,GAAG,CAAC,CAAC;QACb,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACL,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnD,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;CACF"}
@@ -0,0 +1,81 @@
1
+ import { DirectSampling, RtlDeviceProvider } from "../rtlsdr/rtldevice";
2
+ import { SampleReceiver } from "./sample_receiver";
3
+ /** The information in a 'radio' event. */
4
+ export type RadioEventType = {
5
+ type: "started";
6
+ } | {
7
+ type: "stopped";
8
+ } | {
9
+ type: "directSampling";
10
+ active: boolean;
11
+ } | {
12
+ type: "error";
13
+ exception: any;
14
+ };
15
+ /** The type of 'radio' events. */
16
+ export declare class RadioEvent extends CustomEvent<RadioEventType> {
17
+ constructor(e: RadioEventType);
18
+ }
19
+ /** Provides controls to play, stop, and tune the radio. */
20
+ export declare class Radio extends EventTarget {
21
+ private rtlProvider;
22
+ private sampleReceiver;
23
+ private sampleRate;
24
+ /** @param sampleReceiver the object that will receive the radio samples. */
25
+ constructor(rtlProvider: RtlDeviceProvider, sampleReceiver: SampleReceiver, sampleRate: number);
26
+ /** Current state. */
27
+ private state;
28
+ /** Channel to send messages to the state machine. */
29
+ private channel;
30
+ /** Frequency correction factor, in PPM. */
31
+ private frequencyCorrection;
32
+ /** RF gain in dB, or null for automatic. */
33
+ private gain;
34
+ /** Currently tuned frequency. */
35
+ private frequency;
36
+ /** Whether direct sampling mode is enabled. */
37
+ private directSamplingMethod;
38
+ /** Whether the bias tee is enabled. */
39
+ private biasTeeEnabled;
40
+ /** Starts playing the radio. */
41
+ start(): void;
42
+ /** Stops playing the radio. */
43
+ stop(): void;
44
+ /** Returns whether the radio is playing (or scanning). */
45
+ isPlaying(): boolean;
46
+ /** Tunes the radio to this frequency. */
47
+ setFrequency(freq: number): void;
48
+ /** Returns the tuned frequency. */
49
+ getFrequency(): number;
50
+ /** Sets the frequency correction factor, in PPM. */
51
+ setFrequencyCorrection(ppm: number): void;
52
+ /** Returns the current frequency correction factor. */
53
+ getFrequencyCorrection(): number;
54
+ /**
55
+ * Sets the RF gain.
56
+ * @param gain the gain in dB, or null for automatic gain control.
57
+ */
58
+ setGain(gain: number | null): void;
59
+ /**
60
+ * Returns the RF gain.
61
+ * @returns the gain in dB, or null for automatic gain control.
62
+ */
63
+ getGain(): number | null;
64
+ /** Sets the direct sampling method. */
65
+ setDirectSamplingMethod(method: DirectSampling): void;
66
+ /** Returns the current direct sampling method. */
67
+ getDirectSamplingMethod(): DirectSampling;
68
+ /** Changes the sample rate. This change only takes effect when the radio is started. */
69
+ setSampleRate(sampleRate: number): void;
70
+ /** Returns the current sample rate. */
71
+ getSampleRate(): number;
72
+ /** Enables or disables the bias tee. */
73
+ enableBiasTee(enable: boolean): void;
74
+ /** Returns whether the bias tee is enabled. */
75
+ isBiasTeeEnabled(): boolean;
76
+ /** Runs the state machine. */
77
+ private runLoop;
78
+ addEventListener(type: "radio", callback: (e: RadioEvent) => void | null, options?: boolean | AddEventListenerOptions | undefined): void;
79
+ addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions | undefined): void;
80
+ }
81
+ //# sourceMappingURL=radio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio.d.ts","sourceRoot":"","sources":["../../src/radio/radio.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,cAAc,EAAa,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAYnD,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,GAAG,CAAA;CAAE,CAAC;AAEtC,kCAAkC;AAClC,qBAAa,UAAW,SAAQ,WAAW,CAAC,cAAc,CAAC;gBAC7C,CAAC,EAAE,cAAc;CAG9B;AAQD,2DAA2D;AAC3D,qBAAa,KAAM,SAAQ,WAAW;IAGlC,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,UAAU;IAJpB,4EAA4E;gBAElE,WAAW,EAAE,iBAAiB,EAC9B,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,MAAM;IAa5B,qBAAqB;IACrB,OAAO,CAAC,KAAK,CAAQ;IACrB,qDAAqD;IACrD,OAAO,CAAC,OAAO,CAAmB;IAClC,2CAA2C;IAC3C,OAAO,CAAC,mBAAmB,CAAS;IACpC,4CAA4C;IAC5C,OAAO,CAAC,IAAI,CAAgB;IAC5B,iCAAiC;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,+CAA+C;IAC/C,OAAO,CAAC,oBAAoB,CAAiB;IAC7C,uCAAuC;IACvC,OAAO,CAAC,cAAc,CAAU;IAEhC,gCAAgC;IAChC,KAAK;IAIL,+BAA+B;IAC/B,IAAI;IAIJ,0DAA0D;IAC1D,SAAS;IAIT,yCAAyC;IACzC,YAAY,CAAC,IAAI,EAAE,MAAM;IAIzB,mCAAmC;IACnC,YAAY,IAAI,MAAM;IAItB,oDAAoD;IACpD,sBAAsB,CAAC,GAAG,EAAE,MAAM;IAIlC,uDAAuD;IACvD,sBAAsB,IAAI,MAAM;IAIhC;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B;;;OAGG;IACH,OAAO,IAAI,MAAM,GAAG,IAAI;IAIxB,uCAAuC;IACvC,uBAAuB,CAAC,MAAM,EAAE,cAAc;IAI9C,kDAAkD;IAClD,uBAAuB,IAAI,cAAc;IAIzC,wFAAwF;IACxF,aAAa,CAAC,UAAU,EAAE,MAAM;IAIhC,uCAAuC;IACvC,aAAa,IAAI,MAAM;IAIvB,wCAAwC;IACxC,aAAa,CAAC,MAAM,EAAE,OAAO;IAI7B,+CAA+C;IAC/C,gBAAgB,IAAI,OAAO;IAI3B,8BAA8B;YAChB,OAAO;IAoFrB,gBAAgB,CACd,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,EACxC,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS,GACtD,IAAI;IACP,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,GAAG,IAAI,EACnD,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS,GACtD,IAAI;CAYR"}
@@ -0,0 +1,305 @@
1
+ // Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ /** State machine to orchestrate the RTL2832, demodulation, and audio playing. */
15
+ import { U8ToFloat32 } from "../dsp/converters";
16
+ import { RadioError, RadioErrorType } from "../errors";
17
+ import { DirectSampling } from "../rtlsdr/rtldevice";
18
+ import { Channel } from "./msgqueue";
19
+ /** The type of 'radio' events. */
20
+ export class RadioEvent extends CustomEvent {
21
+ constructor(e) {
22
+ super("radio", { detail: e });
23
+ }
24
+ }
25
+ /** Current state. */
26
+ var State;
27
+ (function (State) {
28
+ State[State["OFF"] = 0] = "OFF";
29
+ State[State["PLAYING"] = 1] = "PLAYING";
30
+ })(State || (State = {}));
31
+ /** Provides controls to play, stop, and tune the radio. */
32
+ export class Radio extends EventTarget {
33
+ rtlProvider;
34
+ sampleReceiver;
35
+ sampleRate;
36
+ /** @param sampleReceiver the object that will receive the radio samples. */
37
+ constructor(rtlProvider, sampleReceiver, sampleRate) {
38
+ super();
39
+ this.rtlProvider = rtlProvider;
40
+ this.sampleReceiver = sampleReceiver;
41
+ this.sampleRate = sampleRate;
42
+ this.state = State.OFF;
43
+ this.channel = new Channel();
44
+ this.frequencyCorrection = 0;
45
+ this.gain = null;
46
+ this.frequency = 88500000;
47
+ this.directSamplingMethod = DirectSampling.Off;
48
+ this.biasTeeEnabled = false;
49
+ this.runLoop();
50
+ }
51
+ /** Current state. */
52
+ state;
53
+ /** Channel to send messages to the state machine. */
54
+ channel;
55
+ /** Frequency correction factor, in PPM. */
56
+ frequencyCorrection;
57
+ /** RF gain in dB, or null for automatic. */
58
+ gain;
59
+ /** Currently tuned frequency. */
60
+ frequency;
61
+ /** Whether direct sampling mode is enabled. */
62
+ directSamplingMethod;
63
+ /** Whether the bias tee is enabled. */
64
+ biasTeeEnabled;
65
+ /** Starts playing the radio. */
66
+ start() {
67
+ this.channel.send({ type: "start" });
68
+ }
69
+ /** Stops playing the radio. */
70
+ stop() {
71
+ this.channel.send({ type: "stop" });
72
+ }
73
+ /** Returns whether the radio is playing (or scanning). */
74
+ isPlaying() {
75
+ return this.state != State.OFF;
76
+ }
77
+ /** Tunes the radio to this frequency. */
78
+ setFrequency(freq) {
79
+ this.channel.send({ type: "frequency", value: freq });
80
+ }
81
+ /** Returns the tuned frequency. */
82
+ getFrequency() {
83
+ return this.frequency;
84
+ }
85
+ /** Sets the frequency correction factor, in PPM. */
86
+ setFrequencyCorrection(ppm) {
87
+ this.channel.send({ type: "frequencyCorrection", value: ppm });
88
+ }
89
+ /** Returns the current frequency correction factor. */
90
+ getFrequencyCorrection() {
91
+ return this.frequencyCorrection;
92
+ }
93
+ /**
94
+ * Sets the RF gain.
95
+ * @param gain the gain in dB, or null for automatic gain control.
96
+ */
97
+ setGain(gain) {
98
+ this.channel.send({ type: "gain", value: gain });
99
+ }
100
+ /**
101
+ * Returns the RF gain.
102
+ * @returns the gain in dB, or null for automatic gain control.
103
+ */
104
+ getGain() {
105
+ return this.gain;
106
+ }
107
+ /** Sets the direct sampling method. */
108
+ setDirectSamplingMethod(method) {
109
+ this.channel.send({ type: "directSamplingMethod", value: method });
110
+ }
111
+ /** Returns the current direct sampling method. */
112
+ getDirectSamplingMethod() {
113
+ return this.directSamplingMethod;
114
+ }
115
+ /** Changes the sample rate. This change only takes effect when the radio is started. */
116
+ setSampleRate(sampleRate) {
117
+ this.sampleRate = sampleRate;
118
+ }
119
+ /** Returns the current sample rate. */
120
+ getSampleRate() {
121
+ return this.sampleRate;
122
+ }
123
+ /** Enables or disables the bias tee. */
124
+ enableBiasTee(enable) {
125
+ this.channel.send({ type: "biasTeeEnabled", value: enable });
126
+ }
127
+ /** Returns whether the bias tee is enabled. */
128
+ isBiasTeeEnabled() {
129
+ return this.biasTeeEnabled;
130
+ }
131
+ /** Runs the state machine. */
132
+ async runLoop() {
133
+ let transfers;
134
+ let rtl;
135
+ while (true) {
136
+ let msg = await this.channel.receive();
137
+ try {
138
+ switch (this.state) {
139
+ case State.OFF: {
140
+ if (msg.type == "frequency")
141
+ this.frequency = msg.value;
142
+ if (msg.type == "frequencyCorrection")
143
+ this.frequencyCorrection = msg.value;
144
+ if (msg.type == "gain")
145
+ this.gain = msg.value;
146
+ if (msg.type == "directSamplingMethod")
147
+ this.directSamplingMethod = msg.value;
148
+ if (msg.type == "biasTeeEnabled")
149
+ this.biasTeeEnabled = msg.value;
150
+ if (msg.type != "start")
151
+ continue;
152
+ rtl = await this.rtlProvider.get();
153
+ await rtl.setSampleRate(this.sampleRate);
154
+ await rtl.setFrequencyCorrection(this.frequencyCorrection);
155
+ await rtl.setGain(this.gain);
156
+ await rtl.setDirectSamplingMethod(this.directSamplingMethod);
157
+ await rtl.setCenterFrequency(this.frequency);
158
+ await rtl.resetBuffer();
159
+ transfers = new Transfers(rtl, this.sampleReceiver, this, this.sampleRate);
160
+ transfers.startStream();
161
+ this.state = State.PLAYING;
162
+ this.dispatchEvent(new RadioEvent({ type: "started" }));
163
+ break;
164
+ }
165
+ case State.PLAYING: {
166
+ switch (msg.type) {
167
+ case "frequency":
168
+ if (this.frequency != msg.value) {
169
+ this.frequency = msg.value;
170
+ await rtl.setCenterFrequency(this.frequency);
171
+ }
172
+ break;
173
+ case "gain":
174
+ if (this.gain != msg.value) {
175
+ this.gain = msg.value;
176
+ await rtl.setGain(this.gain);
177
+ }
178
+ break;
179
+ case "frequencyCorrection":
180
+ if (this.frequencyCorrection != msg.value) {
181
+ this.frequencyCorrection = msg.value;
182
+ await rtl.setFrequencyCorrection(this.frequencyCorrection);
183
+ }
184
+ break;
185
+ case "directSamplingMethod":
186
+ if (this.directSamplingMethod != msg.value) {
187
+ this.directSamplingMethod = msg.value;
188
+ await rtl.setDirectSamplingMethod(this.directSamplingMethod);
189
+ }
190
+ break;
191
+ case "biasTeeEnabled":
192
+ if (this.biasTeeEnabled != msg.value) {
193
+ this.biasTeeEnabled = msg.value;
194
+ await rtl.enableBiasTee(this.biasTeeEnabled);
195
+ }
196
+ break;
197
+ case "stop":
198
+ await transfers.stopStream();
199
+ await rtl.close();
200
+ this.state = State.OFF;
201
+ this.dispatchEvent(new RadioEvent({ type: "stopped" }));
202
+ break;
203
+ default:
204
+ // do nothing.
205
+ }
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ catch (e) {
211
+ this.dispatchEvent(new RadioEvent({ type: "error", exception: e }));
212
+ }
213
+ }
214
+ }
215
+ addEventListener(type, callback, options) {
216
+ super.addEventListener(type, callback, options);
217
+ }
218
+ }
219
+ /**
220
+ * USB transfer controller.
221
+ *
222
+ * Maintains 2 active USB transfers. When a transfer ends, it calls
223
+ * the sample receiver's 'receiveSamples' function and starts a new
224
+ * transfer. In this way, there is always a stream of samples coming in.
225
+ */
226
+ class Transfers {
227
+ rtl;
228
+ sampleReceiver;
229
+ radio;
230
+ sampleRate;
231
+ /** Receive this many buffers per second. */
232
+ static BUFS_PER_SEC = 20;
233
+ constructor(rtl, sampleReceiver, radio, sampleRate) {
234
+ this.rtl = rtl;
235
+ this.sampleReceiver = sampleReceiver;
236
+ this.radio = radio;
237
+ this.sampleRate = sampleRate;
238
+ this.samplesPerBuf =
239
+ 512 * Math.ceil(sampleRate / Transfers.BUFS_PER_SEC / 512);
240
+ this.buffersWanted = 0;
241
+ this.buffersRunning = 0;
242
+ this.iqConverter = new U8ToFloat32(this.samplesPerBuf);
243
+ this.directSampling = false;
244
+ this.stopCallback = Transfers.nilCallback;
245
+ }
246
+ samplesPerBuf;
247
+ buffersWanted;
248
+ buffersRunning;
249
+ iqConverter;
250
+ directSampling;
251
+ stopCallback;
252
+ static PARALLEL_BUFFERS = 2;
253
+ /** Starts the transfers as a stream. */
254
+ async startStream() {
255
+ this.sampleReceiver.setSampleRate(this.sampleRate);
256
+ await this.rtl.resetBuffer();
257
+ this.buffersWanted = Transfers.PARALLEL_BUFFERS;
258
+ while (this.buffersRunning < this.buffersWanted) {
259
+ ++this.buffersRunning;
260
+ this.readStream();
261
+ }
262
+ }
263
+ /**
264
+ * Stops the transfer stream.
265
+ * @returns a promise that resolves when the stream is stopped.
266
+ */
267
+ async stopStream() {
268
+ if (this.buffersRunning == 0 && this.buffersWanted == 0)
269
+ return;
270
+ let promise = new Promise((r) => {
271
+ this.stopCallback = r;
272
+ });
273
+ this.buffersWanted = 0;
274
+ return promise;
275
+ }
276
+ /** Runs the transfer stream. */
277
+ async readStream() {
278
+ try {
279
+ while (this.buffersRunning <= this.buffersWanted) {
280
+ const b = await this.rtl.readSamples(this.samplesPerBuf);
281
+ let [I, Q] = this.iqConverter.convert(b.data);
282
+ this.sampleReceiver.receiveSamples(I, Q, b.frequency);
283
+ if (this.directSampling != b.directSampling) {
284
+ this.directSampling = b.directSampling;
285
+ this.radio.dispatchEvent(new RadioEvent({
286
+ type: "directSampling",
287
+ active: this.directSampling,
288
+ }));
289
+ }
290
+ }
291
+ }
292
+ catch (e) {
293
+ let error = new RadioError("Sample transfer was interrupted. Did you unplug your device?", RadioErrorType.UsbTransferError, { cause: e });
294
+ let event = new RadioEvent({ type: "error", exception: error });
295
+ this.radio.dispatchEvent(event);
296
+ }
297
+ --this.buffersRunning;
298
+ if (this.buffersRunning == 0) {
299
+ this.stopCallback();
300
+ this.stopCallback = Transfers.nilCallback;
301
+ }
302
+ }
303
+ static nilCallback() { }
304
+ }
305
+ //# sourceMappingURL=radio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio.js","sourceRoot":"","sources":["../../src/radio/radio.ts"],"names":[],"mappings":"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"}