@livekit/rtc-node 0.11.0 → 0.12.0

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 (153) hide show
  1. package/dist/audio_frame.cjs +94 -0
  2. package/dist/audio_frame.cjs.map +1 -0
  3. package/dist/audio_frame.js +64 -67
  4. package/dist/audio_frame.js.map +1 -1
  5. package/dist/audio_resampler.cjs +153 -0
  6. package/dist/audio_resampler.cjs.map +1 -0
  7. package/dist/audio_resampler.js +129 -134
  8. package/dist/audio_resampler.js.map +1 -1
  9. package/dist/audio_source.cjs +116 -0
  10. package/dist/audio_source.cjs.map +1 -0
  11. package/dist/audio_source.js +92 -85
  12. package/dist/audio_source.js.map +1 -1
  13. package/dist/audio_stream.cjs +104 -0
  14. package/dist/audio_stream.cjs.map +1 -0
  15. package/dist/audio_stream.js +77 -78
  16. package/dist/audio_stream.js.map +1 -1
  17. package/dist/e2ee.cjs +268 -0
  18. package/dist/e2ee.cjs.map +1 -0
  19. package/dist/e2ee.d.ts.map +1 -1
  20. package/dist/e2ee.js +244 -221
  21. package/dist/e2ee.js.map +1 -1
  22. package/dist/ffi_client.cjs +101 -0
  23. package/dist/ffi_client.cjs.map +1 -0
  24. package/dist/ffi_client.js +73 -48
  25. package/dist/ffi_client.js.map +1 -1
  26. package/dist/index.cjs +188 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.js +130 -48
  29. package/dist/index.js.map +1 -1
  30. package/dist/napi/native.d.cjs +17 -0
  31. package/dist/napi/native.d.cjs.map +1 -0
  32. package/dist/napi/native.d.js +1 -0
  33. package/dist/napi/native.d.js.map +1 -0
  34. package/dist/napi/native.d.ts +5 -5
  35. package/dist/native.cjs +301 -0
  36. package/dist/native.d.ts +19 -0
  37. package/dist/native.js +15 -0
  38. package/dist/participant.cjs +388 -0
  39. package/dist/participant.cjs.map +1 -0
  40. package/dist/participant.js +363 -339
  41. package/dist/participant.js.map +1 -1
  42. package/dist/proto/audio_frame_pb.cjs +193 -0
  43. package/dist/proto/audio_frame_pb.cjs.map +1 -0
  44. package/dist/proto/audio_frame_pb.d.ts +8 -8
  45. package/dist/proto/audio_frame_pb.d.ts.map +1 -1
  46. package/dist/proto/audio_frame_pb.js +122 -322
  47. package/dist/proto/audio_frame_pb.js.map +1 -1
  48. package/dist/proto/e2ee_pb.cjs +131 -0
  49. package/dist/proto/e2ee_pb.cjs.map +1 -0
  50. package/dist/proto/e2ee_pb.js +76 -202
  51. package/dist/proto/e2ee_pb.js.map +1 -1
  52. package/dist/proto/ffi_pb.cjs +76 -0
  53. package/dist/proto/ffi_pb.cjs.map +1 -0
  54. package/dist/proto/ffi_pb.d.ts +6 -6
  55. package/dist/proto/ffi_pb.d.ts.map +1 -1
  56. package/dist/proto/ffi_pb.js +39 -98
  57. package/dist/proto/ffi_pb.js.map +1 -1
  58. package/dist/proto/handle_pb.cjs +33 -0
  59. package/dist/proto/handle_pb.cjs.map +1 -0
  60. package/dist/proto/handle_pb.js +6 -22
  61. package/dist/proto/handle_pb.js.map +1 -1
  62. package/dist/proto/participant_pb.cjs +50 -0
  63. package/dist/proto/participant_pb.cjs.map +1 -0
  64. package/dist/proto/participant_pb.d.ts +1 -1
  65. package/dist/proto/participant_pb.d.ts.map +1 -1
  66. package/dist/proto/participant_pb.js +20 -58
  67. package/dist/proto/participant_pb.js.map +1 -1
  68. package/dist/proto/room_pb.cjs +370 -0
  69. package/dist/proto/room_pb.cjs.map +1 -0
  70. package/dist/proto/room_pb.d.ts +16 -16
  71. package/dist/proto/room_pb.d.ts.map +1 -1
  72. package/dist/proto/room_pb.js +245 -638
  73. package/dist/proto/room_pb.js.map +1 -1
  74. package/dist/proto/rpc_pb.cjs +63 -0
  75. package/dist/proto/rpc_pb.cjs.map +1 -0
  76. package/dist/proto/rpc_pb.js +26 -72
  77. package/dist/proto/rpc_pb.js.map +1 -1
  78. package/dist/proto/stats_pb.cjs +256 -0
  79. package/dist/proto/stats_pb.cjs.map +1 -0
  80. package/dist/proto/stats_pb.js +175 -456
  81. package/dist/proto/stats_pb.js.map +1 -1
  82. package/dist/proto/track_pb.cjs +116 -0
  83. package/dist/proto/track_pb.cjs.map +1 -0
  84. package/dist/proto/track_pb.d.ts +3 -3
  85. package/dist/proto/track_pb.d.ts.map +1 -1
  86. package/dist/proto/track_pb.js +68 -174
  87. package/dist/proto/track_pb.js.map +1 -1
  88. package/dist/proto/video_frame_pb.cjs +161 -0
  89. package/dist/proto/video_frame_pb.cjs.map +1 -0
  90. package/dist/proto/video_frame_pb.d.ts +5 -5
  91. package/dist/proto/video_frame_pb.d.ts.map +1 -1
  92. package/dist/proto/video_frame_pb.js +103 -271
  93. package/dist/proto/video_frame_pb.js.map +1 -1
  94. package/dist/room.cjs +440 -0
  95. package/dist/room.cjs.map +1 -0
  96. package/dist/room.js +384 -373
  97. package/dist/room.js.map +1 -1
  98. package/dist/rpc.cjs +89 -0
  99. package/dist/rpc.cjs.map +1 -0
  100. package/dist/rpc.js +59 -63
  101. package/dist/rpc.js.map +1 -1
  102. package/dist/track.cjs +100 -0
  103. package/dist/track.cjs.map +1 -0
  104. package/dist/track.js +66 -62
  105. package/dist/track.js.map +1 -1
  106. package/dist/track_publication.cjs +106 -0
  107. package/dist/track_publication.cjs.map +1 -0
  108. package/dist/track_publication.js +76 -74
  109. package/dist/track_publication.js.map +1 -1
  110. package/dist/transcription.cjs +17 -0
  111. package/dist/transcription.cjs.map +1 -0
  112. package/dist/transcription.js +0 -1
  113. package/dist/transcription.js.map +1 -1
  114. package/dist/types.cjs +17 -0
  115. package/dist/types.cjs.map +1 -0
  116. package/dist/types.js +0 -1
  117. package/dist/types.js.map +1 -1
  118. package/dist/version.cjs +29 -0
  119. package/dist/version.cjs.map +1 -0
  120. package/dist/version.d.ts +1 -1
  121. package/dist/version.js +4 -1
  122. package/dist/version.js.map +1 -1
  123. package/dist/video_frame.cjs +242 -0
  124. package/dist/video_frame.cjs.map +1 -0
  125. package/dist/video_frame.js +212 -201
  126. package/dist/video_frame.js.map +1 -1
  127. package/dist/video_source.cjs +63 -0
  128. package/dist/video_source.cjs.map +1 -0
  129. package/dist/video_source.d.ts.map +1 -1
  130. package/dist/video_source.js +42 -37
  131. package/dist/video_source.js.map +1 -1
  132. package/dist/video_stream.cjs +103 -0
  133. package/dist/video_stream.cjs.map +1 -0
  134. package/dist/video_stream.js +76 -77
  135. package/dist/video_stream.js.map +1 -1
  136. package/package.json +18 -9
  137. package/src/audio_frame.ts +2 -2
  138. package/src/audio_source.ts +2 -2
  139. package/src/e2ee.ts +2 -2
  140. package/src/napi/native.d.ts +5 -5
  141. package/src/proto/audio_frame_pb.ts +12 -12
  142. package/src/proto/e2ee_pb.ts +1 -1
  143. package/src/proto/ffi_pb.ts +13 -13
  144. package/src/proto/handle_pb.ts +1 -1
  145. package/src/proto/participant_pb.ts +3 -3
  146. package/src/proto/room_pb.ts +24 -24
  147. package/src/proto/rpc_pb.ts +1 -1
  148. package/src/proto/stats_pb.ts +1 -1
  149. package/src/proto/track_pb.ts +7 -7
  150. package/src/proto/video_frame_pb.ts +9 -9
  151. package/src/version.ts +1 -1
  152. package/src/video_frame.ts +1 -1
  153. package/src/video_source.ts +5 -1
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var audio_frame_exports = {};
20
+ __export(audio_frame_exports, {
21
+ AudioFrame: () => AudioFrame,
22
+ combineAudioFrames: () => combineAudioFrames
23
+ });
24
+ module.exports = __toCommonJS(audio_frame_exports);
25
+ var import_protobuf = require("@bufbuild/protobuf");
26
+ var import_ffi_client = require("./ffi_client.cjs");
27
+ var import_audio_frame_pb = require("./proto/audio_frame_pb.cjs");
28
+ class AudioFrame {
29
+ // note: if converting from Uint8Array to Int16Array, *do not* use buffer.slice!
30
+ // it is marked unstable by Node and can cause undefined behaviour, such as massive chunks of
31
+ // noise being added to the end.
32
+ // it is recommended to use buffer.subarray instead.
33
+ // XXX(nbsp): add this when writing proper docs
34
+ constructor(data, sampleRate, channels, samplesPerChannel) {
35
+ this.data = data;
36
+ this.sampleRate = sampleRate;
37
+ this.channels = channels;
38
+ this.samplesPerChannel = samplesPerChannel;
39
+ }
40
+ static create(sampleRate, channels, samplesPerChannel) {
41
+ const data = new Int16Array(channels * samplesPerChannel);
42
+ return new AudioFrame(data, sampleRate, channels, samplesPerChannel);
43
+ }
44
+ /** @internal */
45
+ static fromOwnedInfo(owned) {
46
+ const info = owned.info;
47
+ const len = info.numChannels * info.samplesPerChannel * 2;
48
+ const data = import_ffi_client.FfiClient.instance.copyBuffer(info.dataPtr, len);
49
+ new import_ffi_client.FfiHandle(owned.handle.id).dispose();
50
+ return new AudioFrame(
51
+ new Int16Array(data.buffer),
52
+ info.sampleRate,
53
+ info.numChannels,
54
+ info.samplesPerChannel
55
+ );
56
+ }
57
+ /** @internal */
58
+ protoInfo() {
59
+ return (0, import_protobuf.create)(import_audio_frame_pb.AudioFrameBufferInfoSchema, {
60
+ dataPtr: import_ffi_client.FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer)),
61
+ sampleRate: this.sampleRate,
62
+ numChannels: this.channels,
63
+ samplesPerChannel: this.samplesPerChannel
64
+ });
65
+ }
66
+ }
67
+ const combineAudioFrames = (buffer) => {
68
+ if (!Array.isArray(buffer)) {
69
+ return buffer;
70
+ }
71
+ if (buffer.length === 0) {
72
+ throw new Error("buffer is empty");
73
+ }
74
+ const sampleRate = buffer[0].sampleRate;
75
+ const channels = buffer[0].channels;
76
+ let totalSamplesPerChannel = 0;
77
+ for (const frame of buffer) {
78
+ if (frame.sampleRate != sampleRate) {
79
+ throw new Error(`sample rate mismatch: expected ${sampleRate}, got ${frame.sampleRate}`);
80
+ }
81
+ if (frame.channels != channels) {
82
+ throw new Error(`channel mismatch: expected ${channels}, got ${frame.channels}`);
83
+ }
84
+ totalSamplesPerChannel += frame.samplesPerChannel;
85
+ }
86
+ const data = new Int16Array(buffer.map((x) => [...x.data]).flat());
87
+ return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel);
88
+ };
89
+ // Annotate the CommonJS export names for ESM import in node:
90
+ 0 && (module.exports = {
91
+ AudioFrame,
92
+ combineAudioFrames
93
+ });
94
+ //# sourceMappingURL=audio_frame.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/audio_frame.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { create } from '@bufbuild/protobuf';\nimport { FfiClient, FfiHandle } from './ffi_client.js';\nimport type { OwnedAudioFrameBuffer } from './proto/audio_frame_pb.js';\nimport { type AudioFrameBufferInfo, AudioFrameBufferInfoSchema } from './proto/audio_frame_pb.js';\n\nexport class AudioFrame {\n data: Int16Array;\n sampleRate: number;\n channels: number;\n samplesPerChannel: number;\n\n // note: if converting from Uint8Array to Int16Array, *do not* use buffer.slice!\n // it is marked unstable by Node and can cause undefined behaviour, such as massive chunks of\n // noise being added to the end.\n // it is recommended to use buffer.subarray instead.\n // XXX(nbsp): add this when writing proper docs\n constructor(data: Int16Array, sampleRate: number, channels: number, samplesPerChannel: number) {\n this.data = data;\n this.sampleRate = sampleRate;\n this.channels = channels;\n this.samplesPerChannel = samplesPerChannel;\n }\n\n static create(sampleRate: number, channels: number, samplesPerChannel: number): AudioFrame {\n const data = new Int16Array(channels * samplesPerChannel);\n return new AudioFrame(data, sampleRate, channels, samplesPerChannel);\n }\n\n /** @internal */\n static fromOwnedInfo(owned: OwnedAudioFrameBuffer): AudioFrame {\n const info = owned.info!;\n const len = info.numChannels * info.samplesPerChannel * 2; // c_int16\n const data = FfiClient.instance.copyBuffer(info.dataPtr, len);\n new FfiHandle(owned.handle!.id).dispose();\n return new AudioFrame(\n new Int16Array(data.buffer),\n info.sampleRate,\n info.numChannels,\n info.samplesPerChannel,\n );\n }\n\n /** @internal */\n protoInfo(): AudioFrameBufferInfo {\n return create(AudioFrameBufferInfoSchema, {\n dataPtr: FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer)),\n sampleRate: this.sampleRate,\n numChannels: this.channels,\n samplesPerChannel: this.samplesPerChannel,\n });\n }\n}\n\n/**\n * Combines one or more `rtc.AudioFrame` objects into a single `rtc.AudioFrame`.\n *\n * This function concatenates the audio data from multiple frames, ensuring that all frames have\n * the same sample rate and number of channels. It efficiently merges the data by preallocating the\n * necessary memory and copying the frame data without unnecessary reallocations.\n *\n * @param buffer - a single AudioFrame or list thereof\n */\nexport const combineAudioFrames = (buffer: AudioFrame | AudioFrame[]): AudioFrame => {\n if (!Array.isArray(buffer)) {\n return buffer as AudioFrame;\n }\n\n if (buffer.length === 0) {\n throw new Error('buffer is empty');\n }\n\n const sampleRate = buffer[0]!.sampleRate;\n const channels = buffer[0]!.channels;\n\n let totalSamplesPerChannel = 0;\n for (const frame of buffer) {\n if (frame.sampleRate != sampleRate) {\n throw new Error(`sample rate mismatch: expected ${sampleRate}, got ${frame.sampleRate}`);\n }\n\n if (frame.channels != channels) {\n throw new Error(`channel mismatch: expected ${channels}, got ${frame.channels}`);\n }\n\n totalSamplesPerChannel += frame.samplesPerChannel;\n }\n\n const data = new Int16Array(buffer.map((x) => [...x.data]).flat());\n return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,sBAAuB;AACvB,wBAAqC;AAErC,4BAAsE;AAE/D,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWtB,YAAY,MAAkB,YAAoB,UAAkB,mBAA2B;AAC7F,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,OAAO,OAAO,YAAoB,UAAkB,mBAAuC;AACzF,UAAM,OAAO,IAAI,WAAW,WAAW,iBAAiB;AACxD,WAAO,IAAI,WAAW,MAAM,YAAY,UAAU,iBAAiB;AAAA,EACrE;AAAA;AAAA,EAGA,OAAO,cAAc,OAA0C;AAC7D,UAAM,OAAO,MAAM;AACnB,UAAM,MAAM,KAAK,cAAc,KAAK,oBAAoB;AACxD,UAAM,OAAO,4BAAU,SAAS,WAAW,KAAK,SAAS,GAAG;AAC5D,QAAI,4BAAU,MAAM,OAAQ,EAAE,EAAE,QAAQ;AACxC,WAAO,IAAI;AAAA,MACT,IAAI,WAAW,KAAK,MAAM;AAAA,MAC1B,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAGA,YAAkC;AAChC,eAAO,wBAAO,kDAA4B;AAAA,MACxC,SAAS,4BAAU,SAAS,YAAY,IAAI,WAAW,KAAK,KAAK,MAAM,CAAC;AAAA,MACxE,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAWO,MAAM,qBAAqB,CAAC,WAAkD;AACnF,MAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,iBAAiB;AAAA,EACnC;AAEA,QAAM,aAAa,OAAO,CAAC,EAAG;AAC9B,QAAM,WAAW,OAAO,CAAC,EAAG;AAE5B,MAAI,yBAAyB;AAC7B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,cAAc,YAAY;AAClC,YAAM,IAAI,MAAM,kCAAkC,UAAU,SAAS,MAAM,UAAU,EAAE;AAAA,IACzF;AAEA,QAAI,MAAM,YAAY,UAAU;AAC9B,YAAM,IAAI,MAAM,8BAA8B,QAAQ,SAAS,MAAM,QAAQ,EAAE;AAAA,IACjF;AAEA,8BAA0B,MAAM;AAAA,EAClC;AAEA,QAAM,OAAO,IAAI,WAAW,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC;AACjE,SAAO,IAAI,WAAW,MAAM,YAAY,UAAU,sBAAsB;AAC1E;","names":[]}
@@ -1,72 +1,69 @@
1
- // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
- //
3
- // SPDX-License-Identifier: Apache-2.0
4
- import { create } from '@bufbuild/protobuf';
5
- import { FfiClient, FfiHandle } from './ffi_client.js';
6
- import { AudioFrameBufferInfoSchema } from './proto/audio_frame_pb.js';
7
- export class AudioFrame {
8
- // note: if converting from Uint8Array to Int16Array, *do not* use buffer.slice!
9
- // it is marked unstable by Node and can cause undefined behaviour, such as massive chunks of
10
- // noise being added to the end.
11
- // it is recommended to use buffer.subarray instead.
12
- // XXX(nbsp): add this when writing proper docs
13
- constructor(data, sampleRate, channels, samplesPerChannel) {
14
- this.data = data;
15
- this.sampleRate = sampleRate;
16
- this.channels = channels;
17
- this.samplesPerChannel = samplesPerChannel;
18
- }
19
- static create(sampleRate, channels, samplesPerChannel) {
20
- const data = new Int16Array(channels * samplesPerChannel);
21
- return new AudioFrame(data, sampleRate, channels, samplesPerChannel);
22
- }
23
- /** @internal */
24
- static fromOwnedInfo(owned) {
25
- const info = owned.info;
26
- const len = info.numChannels * info.samplesPerChannel * 2; // c_int16
27
- const data = FfiClient.instance.copyBuffer(info.dataPtr, len);
28
- new FfiHandle(owned.handle.id).dispose();
29
- return new AudioFrame(new Int16Array(data.buffer), info.sampleRate, info.numChannels, info.samplesPerChannel);
30
- }
31
- /** @internal */
32
- protoInfo() {
33
- return create(AudioFrameBufferInfoSchema, {
34
- dataPtr: FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer)),
35
- sampleRate: this.sampleRate,
36
- numChannels: this.channels,
37
- samplesPerChannel: this.samplesPerChannel,
38
- });
39
- }
1
+ import { create } from "@bufbuild/protobuf";
2
+ import { FfiClient, FfiHandle } from "./ffi_client.js";
3
+ import { AudioFrameBufferInfoSchema } from "./proto/audio_frame_pb.js";
4
+ class AudioFrame {
5
+ // note: if converting from Uint8Array to Int16Array, *do not* use buffer.slice!
6
+ // it is marked unstable by Node and can cause undefined behaviour, such as massive chunks of
7
+ // noise being added to the end.
8
+ // it is recommended to use buffer.subarray instead.
9
+ // XXX(nbsp): add this when writing proper docs
10
+ constructor(data, sampleRate, channels, samplesPerChannel) {
11
+ this.data = data;
12
+ this.sampleRate = sampleRate;
13
+ this.channels = channels;
14
+ this.samplesPerChannel = samplesPerChannel;
15
+ }
16
+ static create(sampleRate, channels, samplesPerChannel) {
17
+ const data = new Int16Array(channels * samplesPerChannel);
18
+ return new AudioFrame(data, sampleRate, channels, samplesPerChannel);
19
+ }
20
+ /** @internal */
21
+ static fromOwnedInfo(owned) {
22
+ const info = owned.info;
23
+ const len = info.numChannels * info.samplesPerChannel * 2;
24
+ const data = FfiClient.instance.copyBuffer(info.dataPtr, len);
25
+ new FfiHandle(owned.handle.id).dispose();
26
+ return new AudioFrame(
27
+ new Int16Array(data.buffer),
28
+ info.sampleRate,
29
+ info.numChannels,
30
+ info.samplesPerChannel
31
+ );
32
+ }
33
+ /** @internal */
34
+ protoInfo() {
35
+ return create(AudioFrameBufferInfoSchema, {
36
+ dataPtr: FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer)),
37
+ sampleRate: this.sampleRate,
38
+ numChannels: this.channels,
39
+ samplesPerChannel: this.samplesPerChannel
40
+ });
41
+ }
40
42
  }
41
- /**
42
- * Combines one or more `rtc.AudioFrame` objects into a single `rtc.AudioFrame`.
43
- *
44
- * This function concatenates the audio data from multiple frames, ensuring that all frames have
45
- * the same sample rate and number of channels. It efficiently merges the data by preallocating the
46
- * necessary memory and copying the frame data without unnecessary reallocations.
47
- *
48
- * @param buffer - a single AudioFrame or list thereof
49
- */
50
- export const combineAudioFrames = (buffer) => {
51
- if (!Array.isArray(buffer)) {
52
- return buffer;
53
- }
54
- if (buffer.length === 0) {
55
- throw new Error('buffer is empty');
43
+ const combineAudioFrames = (buffer) => {
44
+ if (!Array.isArray(buffer)) {
45
+ return buffer;
46
+ }
47
+ if (buffer.length === 0) {
48
+ throw new Error("buffer is empty");
49
+ }
50
+ const sampleRate = buffer[0].sampleRate;
51
+ const channels = buffer[0].channels;
52
+ let totalSamplesPerChannel = 0;
53
+ for (const frame of buffer) {
54
+ if (frame.sampleRate != sampleRate) {
55
+ throw new Error(`sample rate mismatch: expected ${sampleRate}, got ${frame.sampleRate}`);
56
56
  }
57
- const sampleRate = buffer[0].sampleRate;
58
- const channels = buffer[0].channels;
59
- let totalSamplesPerChannel = 0;
60
- for (const frame of buffer) {
61
- if (frame.sampleRate != sampleRate) {
62
- throw new Error(`sample rate mismatch: expected ${sampleRate}, got ${frame.sampleRate}`);
63
- }
64
- if (frame.channels != channels) {
65
- throw new Error(`channel mismatch: expected ${channels}, got ${frame.channels}`);
66
- }
67
- totalSamplesPerChannel += frame.samplesPerChannel;
57
+ if (frame.channels != channels) {
58
+ throw new Error(`channel mismatch: expected ${channels}, got ${frame.channels}`);
68
59
  }
69
- const data = new Int16Array(buffer.map((x) => [...x.data]).flat());
70
- return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel);
60
+ totalSamplesPerChannel += frame.samplesPerChannel;
61
+ }
62
+ const data = new Int16Array(buffer.map((x) => [...x.data]).flat());
63
+ return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel);
64
+ };
65
+ export {
66
+ AudioFrame,
67
+ combineAudioFrames
71
68
  };
72
69
  //# sourceMappingURL=audio_frame.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio_frame.js","sourceRoot":"","sources":["../src/audio_frame.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"sources":["../src/audio_frame.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { create } from '@bufbuild/protobuf';\nimport { FfiClient, FfiHandle } from './ffi_client.js';\nimport type { OwnedAudioFrameBuffer } from './proto/audio_frame_pb.js';\nimport { type AudioFrameBufferInfo, AudioFrameBufferInfoSchema } from './proto/audio_frame_pb.js';\n\nexport class AudioFrame {\n data: Int16Array;\n sampleRate: number;\n channels: number;\n samplesPerChannel: number;\n\n // note: if converting from Uint8Array to Int16Array, *do not* use buffer.slice!\n // it is marked unstable by Node and can cause undefined behaviour, such as massive chunks of\n // noise being added to the end.\n // it is recommended to use buffer.subarray instead.\n // XXX(nbsp): add this when writing proper docs\n constructor(data: Int16Array, sampleRate: number, channels: number, samplesPerChannel: number) {\n this.data = data;\n this.sampleRate = sampleRate;\n this.channels = channels;\n this.samplesPerChannel = samplesPerChannel;\n }\n\n static create(sampleRate: number, channels: number, samplesPerChannel: number): AudioFrame {\n const data = new Int16Array(channels * samplesPerChannel);\n return new AudioFrame(data, sampleRate, channels, samplesPerChannel);\n }\n\n /** @internal */\n static fromOwnedInfo(owned: OwnedAudioFrameBuffer): AudioFrame {\n const info = owned.info!;\n const len = info.numChannels * info.samplesPerChannel * 2; // c_int16\n const data = FfiClient.instance.copyBuffer(info.dataPtr, len);\n new FfiHandle(owned.handle!.id).dispose();\n return new AudioFrame(\n new Int16Array(data.buffer),\n info.sampleRate,\n info.numChannels,\n info.samplesPerChannel,\n );\n }\n\n /** @internal */\n protoInfo(): AudioFrameBufferInfo {\n return create(AudioFrameBufferInfoSchema, {\n dataPtr: FfiClient.instance.retrievePtr(new Uint8Array(this.data.buffer)),\n sampleRate: this.sampleRate,\n numChannels: this.channels,\n samplesPerChannel: this.samplesPerChannel,\n });\n }\n}\n\n/**\n * Combines one or more `rtc.AudioFrame` objects into a single `rtc.AudioFrame`.\n *\n * This function concatenates the audio data from multiple frames, ensuring that all frames have\n * the same sample rate and number of channels. It efficiently merges the data by preallocating the\n * necessary memory and copying the frame data without unnecessary reallocations.\n *\n * @param buffer - a single AudioFrame or list thereof\n */\nexport const combineAudioFrames = (buffer: AudioFrame | AudioFrame[]): AudioFrame => {\n if (!Array.isArray(buffer)) {\n return buffer as AudioFrame;\n }\n\n if (buffer.length === 0) {\n throw new Error('buffer is empty');\n }\n\n const sampleRate = buffer[0]!.sampleRate;\n const channels = buffer[0]!.channels;\n\n let totalSamplesPerChannel = 0;\n for (const frame of buffer) {\n if (frame.sampleRate != sampleRate) {\n throw new Error(`sample rate mismatch: expected ${sampleRate}, got ${frame.sampleRate}`);\n }\n\n if (frame.channels != channels) {\n throw new Error(`channel mismatch: expected ${channels}, got ${frame.channels}`);\n }\n\n totalSamplesPerChannel += frame.samplesPerChannel;\n }\n\n const data = new Int16Array(buffer.map((x) => [...x.data]).flat());\n return new AudioFrame(data, sampleRate, channels, totalSamplesPerChannel);\n};\n"],"mappings":"AAGA,SAAS,cAAc;AACvB,SAAS,WAAW,iBAAiB;AAErC,SAAoC,kCAAkC;AAE/D,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWtB,YAAY,MAAkB,YAAoB,UAAkB,mBAA2B;AAC7F,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,OAAO,OAAO,YAAoB,UAAkB,mBAAuC;AACzF,UAAM,OAAO,IAAI,WAAW,WAAW,iBAAiB;AACxD,WAAO,IAAI,WAAW,MAAM,YAAY,UAAU,iBAAiB;AAAA,EACrE;AAAA;AAAA,EAGA,OAAO,cAAc,OAA0C;AAC7D,UAAM,OAAO,MAAM;AACnB,UAAM,MAAM,KAAK,cAAc,KAAK,oBAAoB;AACxD,UAAM,OAAO,UAAU,SAAS,WAAW,KAAK,SAAS,GAAG;AAC5D,QAAI,UAAU,MAAM,OAAQ,EAAE,EAAE,QAAQ;AACxC,WAAO,IAAI;AAAA,MACT,IAAI,WAAW,KAAK,MAAM;AAAA,MAC1B,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAGA,YAAkC;AAChC,WAAO,OAAO,4BAA4B;AAAA,MACxC,SAAS,UAAU,SAAS,YAAY,IAAI,WAAW,KAAK,KAAK,MAAM,CAAC;AAAA,MACxE,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAWO,MAAM,qBAAqB,CAAC,WAAkD;AACnF,MAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,iBAAiB;AAAA,EACnC;AAEA,QAAM,aAAa,OAAO,CAAC,EAAG;AAC9B,QAAM,WAAW,OAAO,CAAC,EAAG;AAE5B,MAAI,yBAAyB;AAC7B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,cAAc,YAAY;AAClC,YAAM,IAAI,MAAM,kCAAkC,UAAU,SAAS,MAAM,UAAU,EAAE;AAAA,IACzF;AAEA,QAAI,MAAM,YAAY,UAAU;AAC9B,YAAM,IAAI,MAAM,8BAA8B,QAAQ,SAAS,MAAM,QAAQ,EAAE;AAAA,IACjF;AAEA,8BAA0B,MAAM;AAAA,EAClC;AAEA,QAAM,OAAO,IAAI,WAAW,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC;AACjE,SAAO,IAAI,WAAW,MAAM,YAAY,UAAU,sBAAsB;AAC1E;","names":[]}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var audio_resampler_exports = {};
20
+ __export(audio_resampler_exports, {
21
+ AudioResampler: () => AudioResampler,
22
+ AudioResamplerQuality: () => AudioResamplerQuality
23
+ });
24
+ module.exports = __toCommonJS(audio_resampler_exports);
25
+ var import_protobuf = require("@bufbuild/protobuf");
26
+ var import_audio_frame = require("./audio_frame.cjs");
27
+ var import_ffi_client = require("./ffi_client.cjs");
28
+ var import_audio_frame_pb = require("./proto/audio_frame_pb.cjs");
29
+ var AudioResamplerQuality = ((AudioResamplerQuality2) => {
30
+ AudioResamplerQuality2[AudioResamplerQuality2["QUICK"] = import_audio_frame_pb.SoxQualityRecipe.SOXR_QUALITY_QUICK] = "QUICK";
31
+ AudioResamplerQuality2[AudioResamplerQuality2["LOW"] = import_audio_frame_pb.SoxQualityRecipe.SOXR_QUALITY_LOW] = "LOW";
32
+ AudioResamplerQuality2[AudioResamplerQuality2["MEDIUM"] = import_audio_frame_pb.SoxQualityRecipe.SOXR_QUALITY_MEDIUM] = "MEDIUM";
33
+ AudioResamplerQuality2[AudioResamplerQuality2["HIGH"] = import_audio_frame_pb.SoxQualityRecipe.SOXR_QUALITY_HIGH] = "HIGH";
34
+ AudioResamplerQuality2[AudioResamplerQuality2["VERY_HIGH"] = import_audio_frame_pb.SoxQualityRecipe.SOXR_QUALITY_VERYHIGH] = "VERY_HIGH";
35
+ return AudioResamplerQuality2;
36
+ })(AudioResamplerQuality || {});
37
+ class AudioResampler {
38
+ #inputRate;
39
+ #outputRate;
40
+ #channels;
41
+ #ffiHandle;
42
+ /**
43
+ * Initializes a new AudioResampler.
44
+ *
45
+ * @param inputRate - The sample rate of the input audio data (in Hz).
46
+ * @param outputRate - The desired sample rate of the output audio data (in Hz).
47
+ * @param channels - The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.
48
+ * @param quality - The quality setting for the resampler. Defaults to
49
+ * `AudioResamplerQuality.MEDIUM`.
50
+ */
51
+ constructor(inputRate, outputRate, channels = 1, quality = AudioResamplerQuality.MEDIUM) {
52
+ this.#inputRate = inputRate;
53
+ this.#outputRate = outputRate;
54
+ this.#channels = channels;
55
+ const req = (0, import_protobuf.create)(import_audio_frame_pb.NewSoxResamplerRequestSchema, {
56
+ inputRate,
57
+ outputRate,
58
+ numChannels: channels,
59
+ qualityRecipe: quality,
60
+ inputDataType: import_audio_frame_pb.SoxResamplerDataType.SOXR_DATATYPE_INT16I,
61
+ outputDataType: import_audio_frame_pb.SoxResamplerDataType.SOXR_DATATYPE_INT16I,
62
+ flags: 0
63
+ });
64
+ const res = import_ffi_client.FfiClient.instance.request({
65
+ message: {
66
+ case: "newSoxResampler",
67
+ value: req
68
+ }
69
+ });
70
+ if (res.message.case !== "resampler") {
71
+ throw new Error(res.message.value ?? "Unknown Error");
72
+ }
73
+ this.#ffiHandle = new import_ffi_client.FfiHandle(res.message.value.handle.id);
74
+ }
75
+ /**
76
+ * Push audio data into the resampler and retrieve any available resampled data.
77
+ *
78
+ * This method accepts audio data, resamples it according to the configured input and output rates,
79
+ * and returns any resampled data that is available after processing the input.
80
+ *
81
+ * @param data - The audio frame to resample
82
+ *
83
+ * @returns A list of {@link AudioFrame} objects containing the resampled audio data. The list may
84
+ * be empty if no output data is available yet.
85
+ */
86
+ push(data) {
87
+ const req = (0, import_protobuf.create)(import_audio_frame_pb.PushSoxResamplerRequestSchema, {
88
+ resamplerHandle: this.#ffiHandle.handle,
89
+ dataPtr: data.protoInfo().dataPtr,
90
+ size: data.data.byteLength
91
+ });
92
+ const res = import_ffi_client.FfiClient.instance.request({
93
+ message: {
94
+ case: "pushSoxResampler",
95
+ value: req
96
+ }
97
+ });
98
+ if (res.error) {
99
+ throw new Error(res.error);
100
+ }
101
+ if (!res.outputPtr) {
102
+ return [];
103
+ }
104
+ const outputData = import_ffi_client.FfiClient.instance.copyBuffer(res.outputPtr, res.size);
105
+ return [
106
+ new import_audio_frame.AudioFrame(
107
+ new Int16Array(outputData.buffer),
108
+ this.#outputRate,
109
+ this.#channels,
110
+ Math.trunc(outputData.length / this.#channels / 2)
111
+ )
112
+ ];
113
+ }
114
+ /**
115
+ * Flush any remaining audio data through the resampler and retrieve the resampled data.
116
+ *
117
+ * @remarks
118
+ * This method should be called when no more input data will be provided to ensure that all
119
+ * internal buffers are processed and all resampled data is output.
120
+ */
121
+ flush() {
122
+ const req = (0, import_protobuf.create)(import_audio_frame_pb.FlushSoxResamplerRequestSchema, {
123
+ resamplerHandle: this.#ffiHandle.handle
124
+ });
125
+ const res = import_ffi_client.FfiClient.instance.request({
126
+ message: {
127
+ case: "flushSoxResampler",
128
+ value: req
129
+ }
130
+ });
131
+ if (res.error) {
132
+ throw new Error(res.error);
133
+ }
134
+ if (!res.outputPtr) {
135
+ return [];
136
+ }
137
+ const outputData = import_ffi_client.FfiClient.instance.copyBuffer(res.outputPtr, res.size);
138
+ return [
139
+ new import_audio_frame.AudioFrame(
140
+ new Int16Array(outputData.buffer),
141
+ this.#outputRate,
142
+ this.#channels,
143
+ Math.trunc(outputData.length / this.#channels / 2)
144
+ )
145
+ ];
146
+ }
147
+ }
148
+ // Annotate the CommonJS export names for ESM import in node:
149
+ 0 && (module.exports = {
150
+ AudioResampler,
151
+ AudioResamplerQuality
152
+ });
153
+ //# sourceMappingURL=audio_resampler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/audio_resampler.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { create } from '@bufbuild/protobuf';\nimport { AudioFrame } from './audio_frame.js';\nimport { FfiClient, FfiHandle } from './ffi_client.js';\nimport type {\n FlushSoxResamplerResponse,\n NewSoxResamplerResponse,\n PushSoxResamplerResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n FlushSoxResamplerRequestSchema,\n NewSoxResamplerRequestSchema,\n PushSoxResamplerRequestSchema,\n SoxQualityRecipe,\n SoxResamplerDataType,\n} from './proto/audio_frame_pb.js';\n\n/**\n * Resampler quality. Higher quality settings result in better audio quality but require more\n * processing power.\n */\nexport enum AudioResamplerQuality {\n QUICK = SoxQualityRecipe.SOXR_QUALITY_QUICK,\n LOW = SoxQualityRecipe.SOXR_QUALITY_LOW,\n MEDIUM = SoxQualityRecipe.SOXR_QUALITY_MEDIUM,\n HIGH = SoxQualityRecipe.SOXR_QUALITY_HIGH,\n VERY_HIGH = SoxQualityRecipe.SOXR_QUALITY_VERYHIGH,\n}\n\n/**\n * AudioResampler provides functionality to resample audio data from an input sample rate to\n * an output sample rate using the Sox resampling library. It supports multiple channels and\n * configurable resampling quality.\n */\nexport class AudioResampler {\n #inputRate: number;\n #outputRate: number;\n #channels: number;\n #ffiHandle: FfiHandle;\n\n /**\n * Initializes a new AudioResampler.\n *\n * @param inputRate - The sample rate of the input audio data (in Hz).\n * @param outputRate - The desired sample rate of the output audio data (in Hz).\n * @param channels - The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.\n * @param quality - The quality setting for the resampler. Defaults to\n * `AudioResamplerQuality.MEDIUM`.\n */\n constructor(\n inputRate: number,\n outputRate: number,\n channels = 1,\n quality = AudioResamplerQuality.MEDIUM,\n ) {\n this.#inputRate = inputRate;\n this.#outputRate = outputRate;\n this.#channels = channels;\n\n const req = create(NewSoxResamplerRequestSchema, {\n inputRate,\n outputRate,\n numChannels: channels,\n qualityRecipe: quality as number as SoxQualityRecipe,\n inputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,\n outputDataType: SoxResamplerDataType.SOXR_DATATYPE_INT16I,\n flags: 0,\n });\n\n const res = FfiClient.instance.request<NewSoxResamplerResponse>({\n message: {\n case: 'newSoxResampler',\n value: req,\n },\n });\n\n if (res.message.case !== 'resampler') {\n throw new Error(res.message.value ?? 'Unknown Error');\n }\n\n this.#ffiHandle = new FfiHandle(res.message.value.handle!.id);\n }\n\n /**\n * Push audio data into the resampler and retrieve any available resampled data.\n *\n * This method accepts audio data, resamples it according to the configured input and output rates,\n * and returns any resampled data that is available after processing the input.\n *\n * @param data - The audio frame to resample\n *\n * @returns A list of {@link AudioFrame} objects containing the resampled audio data. The list may\n * be empty if no output data is available yet.\n */\n push(data: AudioFrame): AudioFrame[] {\n const req = create(PushSoxResamplerRequestSchema, {\n resamplerHandle: this.#ffiHandle.handle,\n dataPtr: data.protoInfo().dataPtr,\n size: data.data.byteLength,\n });\n\n const res = FfiClient.instance.request<PushSoxResamplerResponse>({\n message: {\n case: 'pushSoxResampler',\n value: req,\n },\n });\n\n if (res.error) {\n throw new Error(res.error);\n }\n\n if (!res.outputPtr) {\n return [];\n }\n\n const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);\n return [\n new AudioFrame(\n new Int16Array(outputData.buffer),\n this.#outputRate,\n this.#channels,\n Math.trunc(outputData.length / this.#channels / 2),\n ),\n ];\n }\n\n /**\n * Flush any remaining audio data through the resampler and retrieve the resampled data.\n *\n * @remarks\n * This method should be called when no more input data will be provided to ensure that all\n * internal buffers are processed and all resampled data is output.\n */\n flush(): AudioFrame[] {\n const req = create(FlushSoxResamplerRequestSchema, {\n resamplerHandle: this.#ffiHandle.handle,\n });\n\n const res = FfiClient.instance.request<FlushSoxResamplerResponse>({\n message: {\n case: 'flushSoxResampler',\n value: req,\n },\n });\n\n if (res.error) {\n throw new Error(res.error);\n }\n\n if (!res.outputPtr) {\n return [];\n }\n\n const outputData = FfiClient.instance.copyBuffer(res.outputPtr, res.size);\n return [\n new AudioFrame(\n new Int16Array(outputData.buffer),\n this.#outputRate,\n this.#channels,\n Math.trunc(outputData.length / this.#channels / 2),\n ),\n ];\n }\n}\n"],"mappings":"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","names":["AudioResamplerQuality"]}