@4players/odin-plugin-web 1.0.0-alpha.9 → 1.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 (54) hide show
  1. package/README.md +1 -1
  2. package/cmake/dependencies.cmake +31 -0
  3. package/cmake/options.cmake +53 -0
  4. package/esbuild.config.ts +49 -0
  5. package/lib/plugin/index.d.ts +42 -49
  6. package/lib/plugin/index.js +1 -292
  7. package/lib/worker/shared.js +1 -0
  8. package/lib/worker/unshared.js +1 -0
  9. package/package.json +34 -29
  10. package/lib/plugin/audioController.d.ts +0 -107
  11. package/lib/plugin/audioController.js +0 -488
  12. package/lib/plugin/config.d.ts +0 -10
  13. package/lib/plugin/config.js +0 -10
  14. package/lib/plugin/connectionPool.d.ts +0 -16
  15. package/lib/plugin/connectionPool.js +0 -110
  16. package/lib/plugin/mainConnection.d.ts +0 -39
  17. package/lib/plugin/mainConnection.js +0 -293
  18. package/lib/plugin/roomConnection.d.ts +0 -36
  19. package/lib/plugin/roomConnection.js +0 -303
  20. package/lib/plugin/rpcConnection.d.ts +0 -48
  21. package/lib/plugin/rpcConnection.js +0 -234
  22. package/lib/plugin/token.d.ts +0 -17
  23. package/lib/plugin/token.js +0 -78
  24. package/lib/wasm/index.d.ts +0 -97
  25. package/lib/worker/buffers.d.ts +0 -42
  26. package/lib/worker/buffers.js +0 -79
  27. package/lib/worker/common.d.ts +0 -45
  28. package/lib/worker/common.js +0 -7
  29. package/lib/worker/config.d.ts +0 -8
  30. package/lib/worker/config.js +0 -11
  31. package/lib/worker/index.d.ts +0 -3
  32. package/lib/worker/index.js +0 -1
  33. package/lib/worker/memory.d.ts +0 -9
  34. package/lib/worker/memory.js +0 -29
  35. package/lib/worker/messages.d.ts +0 -14
  36. package/lib/worker/messages.js +0 -15
  37. package/lib/worker/packet.d.ts +0 -11
  38. package/lib/worker/packet.js +0 -59
  39. package/lib/worker/shared/capture.d.ts +0 -28
  40. package/lib/worker/shared/capture.js +0 -63
  41. package/lib/worker/shared/index.d.ts +0 -3
  42. package/lib/worker/shared/index.js +0 -148
  43. package/lib/worker/shared/messages.d.ts +0 -67
  44. package/lib/worker/shared/messages.js +0 -64
  45. package/lib/worker/shared/playback.d.ts +0 -21
  46. package/lib/worker/shared/playback.js +0 -78
  47. package/lib/worker/unshared/capture.d.ts +0 -28
  48. package/lib/worker/unshared/capture.js +0 -66
  49. package/lib/worker/unshared/index.d.ts +0 -3
  50. package/lib/worker/unshared/index.js +0 -171
  51. package/lib/worker/unshared/messages.d.ts +0 -81
  52. package/lib/worker/unshared/messages.js +0 -80
  53. package/lib/worker/unshared/playback.d.ts +0 -23
  54. package/lib/worker/unshared/playback.js +0 -83
@@ -1,9 +0,0 @@
1
- import type { OdinWasm } from '../../lib/wasm';
2
- export declare function malloc(wasm: typeof OdinWasm, element: 'f32', length: number): Float32Array;
3
- export declare function malloc(wasm: typeof OdinWasm, element: 'u32', length: number): Uint32Array;
4
- export declare function malloc(wasm: typeof OdinWasm, element: 'i32', length: number): Int32Array;
5
- export declare function malloc(wasm: typeof OdinWasm, element: 'u8', length: number): Uint8Array;
6
- export declare function free(wasm: typeof OdinWasm, array: Float32Array): void;
7
- export declare function free(wasm: typeof OdinWasm, array: Uint32Array): void;
8
- export declare function free(wasm: typeof OdinWasm, array: Int32Array): void;
9
- export declare function free(wasm: typeof OdinWasm, array: Uint8Array): void;
@@ -1,29 +0,0 @@
1
- /* eslint-disable no-redeclare */
2
- export function malloc(wasm, element, length) {
3
- let heap;
4
- switch (element) {
5
- case 'f32':
6
- heap = wasm.HEAPF32;
7
- break;
8
- case 'u32':
9
- heap = wasm.HEAPU32;
10
- break;
11
- case 'i32':
12
- heap = wasm.HEAP32;
13
- break;
14
- case 'u8':
15
- heap = wasm.HEAPU8;
16
- break;
17
- default:
18
- throw new Error(`allocating ${element} is not supported`);
19
- }
20
- const pointer = wasm._malloc(length * heap.BYTES_PER_ELEMENT);
21
- if (pointer === 0 || pointer % heap.BYTES_PER_ELEMENT !== 0) {
22
- throw new Error(`failed allocating a ${length} ${element} array`);
23
- }
24
- const start = pointer / heap.BYTES_PER_ELEMENT;
25
- return heap.subarray(start, start + length);
26
- }
27
- export function free(wasm, array) {
28
- wasm._free(array.byteOffset);
29
- }
@@ -1,14 +0,0 @@
1
- import { Result } from '@4players/odin-common';
2
- export type Messages = Record<string, unknown>;
3
- export type Message<Name, Values> = [Name, Values];
4
- export type Inflate<T extends Messages> = {
5
- [Name in keyof T]: Message<Name, T[Name]>;
6
- }[keyof T];
7
- export type MessageResult<T extends Messages> = Result<Inflate<T> | 'closed'>;
8
- export declare function send<T extends Messages>(port: {
9
- postMessage(message: unknown, transfer?: Transferable[]): void;
10
- }, message: Inflate<T>, transfer?: Transferable[]): void;
11
- export declare function waitFor<T extends Messages, Name extends Extract<keyof T, string>>(port: {
12
- addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
13
- removeEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
14
- }, name: Name): Promise<T[Name]>;
@@ -1,15 +0,0 @@
1
- export function send(port, message, transfer) {
2
- return port.postMessage(message, transfer);
3
- }
4
- export function waitFor(port, name) {
5
- return new Promise((accept) => {
6
- const listener = (event) => {
7
- const [eventName, eventValues] = event.data;
8
- if (eventName === name) {
9
- accept(event.data[1]);
10
- port.removeEventListener('message', listener);
11
- }
12
- };
13
- port.addEventListener('message', listener);
14
- });
15
- }
@@ -1,11 +0,0 @@
1
- import { Result } from '@4players/odin-common';
2
- export declare class Packet {
3
- readonly mediaIds: number[];
4
- readonly sequenceNumber: number;
5
- readonly timeStamp: number;
6
- readonly isEndOfSpurt: boolean;
7
- readonly payload: Uint8Array;
8
- static parse(bytes: Uint8Array): Result<Packet>;
9
- constructor(mediaIds: number[], sequenceNumber: number, timeStamp: number, isEndOfSpurt: boolean, payload: Uint8Array);
10
- toBytes(): Uint8Array;
11
- }
@@ -1,59 +0,0 @@
1
- import { failure, msgpackDecode, msgpackEncode, success, } from '@4players/odin-common';
2
- export class Packet {
3
- static parse(bytes) {
4
- let parsed;
5
- try {
6
- parsed = msgpackDecode(bytes);
7
- }
8
- catch (error) {
9
- return failure('not valid msgpack');
10
- }
11
- if (!Array.isArray(parsed))
12
- return failure('container must be an array');
13
- if (parsed.length < 6)
14
- return failure('missing fields');
15
- if (parsed[0] !== 1)
16
- return failure('unknown type');
17
- if (!Array.isArray(parsed[1]))
18
- return failure('media ids must be an array');
19
- if (!parsed[1].every((entry) => typeof entry === 'number')) {
20
- return failure('media ids must be numbers');
21
- }
22
- if (typeof parsed[2] !== 'number') {
23
- return failure('sequence number must be a number');
24
- }
25
- if (typeof parsed[3] !== 'number') {
26
- return failure('timestamp must be a number');
27
- }
28
- if (typeof parsed[4] !== 'number')
29
- return failure('flags must be a number');
30
- const mediaIds = parsed[1];
31
- const sequenceNumber = parsed[2] >>> 0;
32
- const timeStamp = parsed[3] >>> 0;
33
- const flags = parsed[4];
34
- const isEndOfSpurt = (flags & 0x01) !== 0;
35
- const payload = parsed[parsed.length - 1];
36
- if (!(payload instanceof Uint8Array)) {
37
- return failure('payload must be bytes');
38
- }
39
- return success(new Packet(mediaIds, sequenceNumber, timeStamp, isEndOfSpurt, payload));
40
- }
41
- constructor(mediaIds, sequenceNumber, timeStamp, isEndOfSpurt, payload) {
42
- this.mediaIds = mediaIds;
43
- this.sequenceNumber = sequenceNumber;
44
- this.timeStamp = timeStamp;
45
- this.isEndOfSpurt = isEndOfSpurt;
46
- this.payload = payload;
47
- }
48
- toBytes() {
49
- const flags = Number(this.isEndOfSpurt);
50
- return new Uint8Array(msgpackEncode([
51
- 1,
52
- this.mediaIds,
53
- this.sequenceNumber >>> 0,
54
- this.timeStamp >>> 0,
55
- flags,
56
- this.payload,
57
- ]));
58
- }
59
- }
@@ -1,28 +0,0 @@
1
- /// <reference lib="webworker" />
2
- import type { OdinWasm } from '../../../lib/wasm';
3
- import { EncoderInformationBuffer, SampleBuffer } from '../buffers';
4
- import type { VadConfig } from '../common';
5
- export declare class Capture {
6
- readonly sampleRate: number;
7
- readonly wasm: typeof OdinWasm;
8
- readonly encoder: OdinWasm.Encoder;
9
- readonly samples: SampleBuffer;
10
- readonly information: EncoderInformationBuffer;
11
- readonly outBuffer: Uint8Array;
12
- id: number;
13
- sequenceNumber: number;
14
- timestamp: number;
15
- connections: Array<{
16
- id: number;
17
- mediaIds: number[];
18
- }>;
19
- active: boolean;
20
- constructor(sampleRate: number, wasm: typeof OdinWasm);
21
- setVad(config: VadConfig): void;
22
- setMedias(connections: Array<{
23
- id: number;
24
- mediaIds: number[];
25
- }>): void;
26
- close(): void;
27
- tick(): void;
28
- }
@@ -1,63 +0,0 @@
1
- /// <reference lib="WebWorker" />
2
- import { createEncoderInformationBuffer, createSampleBuffer, freeEncoderInformationBuffer, freeSampleBuffer, getSamples, } from '../buffers';
3
- import { AdditionalCaptureBlocks, VadPreload } from '../config';
4
- import { free, malloc } from '../memory';
5
- import { send } from '../messages';
6
- import { Packet } from '../packet';
7
- export class Capture {
8
- constructor(sampleRate, wasm) {
9
- this.sampleRate = sampleRate;
10
- this.wasm = wasm;
11
- this.id = -1;
12
- this.sequenceNumber = (Math.random() * Math.pow(2, 32)) >> 0;
13
- this.timestamp = (Math.random() * Math.pow(2, 32)) >> 0;
14
- this.connections = [];
15
- this.active = false;
16
- this.encoder = new wasm.Encoder(sampleRate,
17
- /* fec */ 15,
18
- /* voip */ true, VadPreload);
19
- this.samples = createSampleBuffer(this.wasm, sampleRate, 2 + VadPreload + AdditionalCaptureBlocks, false);
20
- this.information = createEncoderInformationBuffer(this.wasm);
21
- this.outBuffer = malloc(this.wasm, 'u8', 1270 /* educated guess */);
22
- }
23
- setVad(config) {
24
- var _a, _b, _c, _d, _e, _f, _g, _h;
25
- this.encoder.set_volume_gate(config.volumeGate !== undefined, (_b = (_a = config.volumeGate) === null || _a === void 0 ? void 0 : _a.attackThreshold) !== null && _b !== void 0 ? _b : 0, (_d = (_c = config.volumeGate) === null || _c === void 0 ? void 0 : _c.releaseThreshold) !== null && _d !== void 0 ? _d : 0);
26
- this.encoder.set_speech_detection(config.voiceActivity !== undefined, (_f = (_e = config.voiceActivity) === null || _e === void 0 ? void 0 : _e.attackThreshold) !== null && _f !== void 0 ? _f : 0, (_h = (_g = config.voiceActivity) === null || _g === void 0 ? void 0 : _g.releaseThreshold) !== null && _h !== void 0 ? _h : 0);
27
- }
28
- setMedias(connections) {
29
- this.connections = connections.filter(({ mediaIds }) => mediaIds.length > 0);
30
- }
31
- close() {
32
- freeSampleBuffer(this.wasm, this.samples);
33
- freeEncoderInformationBuffer(this.wasm, this.information);
34
- free(this.wasm, this.outBuffer);
35
- this.encoder.delete();
36
- }
37
- tick() {
38
- this.id += 1;
39
- this.encoder.push(getSamples(this.samples, this.id % this.samples.length).byteOffset, this.information.values.byteOffset);
40
- while (true) {
41
- const n = this.encoder.pop(this.connections.length === 0 ? 0 : this.outBuffer.byteOffset, this.outBuffer.length);
42
- if (n === 0)
43
- break;
44
- if (n < 0) {
45
- console.error(`failed encoding packet: ${n}`);
46
- return;
47
- }
48
- this.timestamp = (this.timestamp + 1800) >> 0; /* 20ms 90kHz */
49
- if (n === 1)
50
- continue;
51
- this.sequenceNumber = (this.sequenceNumber + 1) >> 0;
52
- const isEndOfSpurt = this.active && !this.encoder.active;
53
- this.active = this.encoder.active;
54
- for (const connection of this.connections) {
55
- const packet = new Packet(connection.mediaIds, this.sequenceNumber, this.timestamp, isEndOfSpurt, this.outBuffer.subarray(0, n));
56
- send(globalThis, [
57
- 'sendPacket',
58
- { connectionId: connection.id, packet: packet.toBytes() },
59
- ]);
60
- }
61
- }
62
- }
63
- }
@@ -1,3 +0,0 @@
1
- import { CaptureSink, CaptureWorker, PlaybackWorker } from '../common';
2
- export declare function createCaptureWorker(context: AudioContext, sink: CaptureSink, workerPromise: Promise<Worker>, workletPromise: Promise<AudioWorkletNode>): Promise<CaptureWorker>;
3
- export declare function createPlaybackWorker(audioContext: AudioContext, workerPromise: Promise<Worker>, workletPromise: Promise<AudioWorkletNode>): Promise<PlaybackWorker>;
@@ -1,148 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { getDecoderRmsDBFS, getEncoderActive, getEncoderRmsDBFS, getEncoderSpeechProbability, setDecoderVolume, setEncoderVolume, setGlobalDecoderVolume, } from '../buffers';
11
- import { Silence, mergeIds, } from '../common';
12
- import { send, waitFor } from '../messages';
13
- class CaptureWorkerImpl {
14
- constructor(worklet, worker, information, sink) {
15
- this.worklet = worklet;
16
- this.worker = worker;
17
- this.information = information;
18
- this.sink = sink;
19
- worker.addEventListener('message', this.onMessages.bind(this));
20
- }
21
- get context() {
22
- return this.worklet.context;
23
- }
24
- get activity() {
25
- return {
26
- isSilent: !getEncoderActive(this.information),
27
- rmsDBFS: getEncoderRmsDBFS(this.information),
28
- };
29
- }
30
- get speechProbability() {
31
- return getEncoderSpeechProbability(this.information);
32
- }
33
- setMedias(connections) {
34
- send(this.worker, ['captureSetMedias', { connections }]);
35
- }
36
- setVad(config) {
37
- send(this.worker, ['captureSetVad', config]);
38
- }
39
- setVolume(value) {
40
- setEncoderVolume(this.information, value);
41
- }
42
- close() {
43
- send(this.worklet.port, ['close', undefined]);
44
- send(this.worker, ['close', undefined]);
45
- }
46
- onMessages(event) {
47
- const [name, values] = event.data;
48
- switch (name) {
49
- case 'sendPacket':
50
- this.sink(values.connectionId, values.packet);
51
- break;
52
- }
53
- }
54
- }
55
- export function createCaptureWorker(context, sink, workerPromise, workletPromise) {
56
- return __awaiter(this, void 0, void 0, function* () {
57
- const { port1, port2 } = new MessageChannel();
58
- const [worker, worklet] = yield Promise.all([workerPromise, workletPromise]);
59
- send(worker, ['captureInit', { sampleRate: context.sampleRate, workletPort: port1 }], [port1]);
60
- const { sampleBuffer, informationBuffer } = yield waitFor(worker, 'captureReady');
61
- send(worklet.port, ['init', { workerPort: port2, sampleBuffer }], [port2]);
62
- return new CaptureWorkerImpl(worklet, worker, informationBuffer, sink);
63
- });
64
- }
65
- class PlaybackWorkerImpl {
66
- constructor(audioContext, worklet, worker, information) {
67
- this.audioContext = audioContext;
68
- this.worklet = worklet;
69
- this.worker = worker;
70
- this.information = information;
71
- this.availableIndexes = [];
72
- this.medias = new Map();
73
- }
74
- receivePacket(connectionId, packet) {
75
- send(this.worker, ['playbackReceivePacket', { connectionId, packet }], [packet.buffer]);
76
- }
77
- addMedias(connectionId, mediaIds) {
78
- console.log('addMedias', connectionId, mediaIds);
79
- const added = [];
80
- for (const mediaId of mediaIds) {
81
- const index = this._GetFreeIndex();
82
- if (index === undefined)
83
- continue;
84
- this.medias.set(mergeIds({ connectionId, mediaId }), { index });
85
- added.push({ connectionId, mediaId, index });
86
- }
87
- send(this.worker, [
88
- 'playbackUpdateMedias',
89
- { added, removed: [] },
90
- ]);
91
- }
92
- removeMedias(connectionId, mediaIds) {
93
- const removed = [];
94
- for (const mediaId of mediaIds) {
95
- const id = mergeIds({ connectionId, mediaId });
96
- const media = this.medias.get(id);
97
- if (media === undefined)
98
- continue;
99
- this.medias.delete(id);
100
- this.availableIndexes.push(media.index);
101
- removed.push({ connectionId, mediaId, index: media.index });
102
- }
103
- send(this.worker, [
104
- 'playbackUpdateMedias',
105
- { added: [], removed },
106
- ]);
107
- }
108
- getActivity(id) {
109
- const entry = this.medias.get(mergeIds(id));
110
- if (entry === undefined)
111
- return undefined;
112
- const value = getDecoderRmsDBFS(this.information, entry.index);
113
- return value === 0 ? Silence : { isSilent: false, rmsDBFS: value };
114
- }
115
- setGlobalVolume(value) {
116
- setGlobalDecoderVolume(this.information, value);
117
- }
118
- setVolume(id, value) {
119
- const entry = this.medias.get(mergeIds(id));
120
- if (entry !== undefined) {
121
- setDecoderVolume(this.information, entry.index, value);
122
- }
123
- }
124
- close() {
125
- send(this.worker, ['close', undefined]);
126
- send(this.worklet.port, ['close', undefined]);
127
- }
128
- _GetFreeIndex() {
129
- const result = this.availableIndexes.pop();
130
- if (result !== undefined)
131
- return result;
132
- if (this.information.length > this.medias.size)
133
- return this.medias.size;
134
- return undefined;
135
- }
136
- }
137
- export function createPlaybackWorker(audioContext, workerPromise, workletPromise) {
138
- return __awaiter(this, void 0, void 0, function* () {
139
- const { port1, port2 } = new MessageChannel();
140
- const [worker, worklet] = yield Promise.all([workerPromise, workletPromise]);
141
- send(worker, ['playbackInit', { workletPort: port1 }], [port1]);
142
- const { informationBuffer, sampleBuffer } = yield waitFor(worker, 'playbackReady');
143
- setGlobalDecoderVolume(informationBuffer, 1);
144
- send(worklet.port, ['init', { sampleBuffer, workerPort: port2 }], [port2]);
145
- worklet.connect(audioContext.destination);
146
- return new PlaybackWorkerImpl(audioContext, worklet, worker, informationBuffer);
147
- });
148
- }
@@ -1,67 +0,0 @@
1
- import { VadConfig } from '../common';
2
- import { DecoderInformationBuffer, EncoderInformationBuffer, SampleBuffer } from '../buffers';
3
- import { Inflate } from '../messages';
4
- export type CaptureWorkletMessages = {
5
- init: {
6
- sampleBuffer: SampleBuffer;
7
- workerPort: MessagePort;
8
- };
9
- close: void;
10
- };
11
- export type PlaybackWorkletMessages = {
12
- init: {
13
- sampleBuffer: SampleBuffer;
14
- workerPort: MessagePort;
15
- };
16
- close: void;
17
- };
18
- export type WorkerMessages = {
19
- captureInit: {
20
- sampleRate: number;
21
- workletPort: MessagePort;
22
- };
23
- captureSetMedias: {
24
- connections: Array<{
25
- id: number;
26
- mediaIds: number[];
27
- }>;
28
- };
29
- captureSetVad: VadConfig;
30
- captureTick: void;
31
- playbackInit: {
32
- workletPort: MessagePort;
33
- };
34
- playbackUpdateMedias: {
35
- added: Array<{
36
- index: number;
37
- connectionId: number;
38
- mediaId: number;
39
- }>;
40
- removed: Array<{
41
- index: number;
42
- connectionId: number;
43
- mediaId: number;
44
- }>;
45
- };
46
- playbackReceivePacket: {
47
- connectionId: number;
48
- packet: Uint8Array;
49
- };
50
- playbackTick: void;
51
- close: void;
52
- };
53
- export type MainMessages = {
54
- sendPacket: {
55
- connectionId: number;
56
- packet: Uint8Array;
57
- };
58
- captureReady: {
59
- informationBuffer: EncoderInformationBuffer;
60
- sampleBuffer: SampleBuffer;
61
- };
62
- playbackReady: {
63
- informationBuffer: DecoderInformationBuffer;
64
- sampleBuffer: SampleBuffer;
65
- };
66
- };
67
- export declare function onMessage(event: MessageEvent<Inflate<WorkerMessages>>): void;
@@ -1,64 +0,0 @@
1
- import LoadOdinWasm from '../../../lib/wasm';
2
- import { send } from '../messages';
3
- import { Capture } from './capture';
4
- import { Playback } from './playback';
5
- let playback;
6
- let capture;
7
- export function onMessage(event) {
8
- handle(event.data);
9
- }
10
- function handle(message) {
11
- const [name, values] = message;
12
- switch (name) {
13
- case 'playbackInit':
14
- playback = new Playback(LoadOdinWasm());
15
- values.workletPort.onmessage = (event) => onMessage(event);
16
- send(globalThis, [
17
- 'playbackReady',
18
- {
19
- informationBuffer: playback.information,
20
- sampleBuffer: playback.sampleBuffer,
21
- },
22
- ]);
23
- break;
24
- case 'playbackReceivePacket':
25
- playback === null || playback === void 0 ? void 0 : playback.receivePacket(values.connectionId, values.packet);
26
- break;
27
- case 'playbackUpdateMedias':
28
- for (const { index, connectionId, mediaId } of values.removed) {
29
- playback === null || playback === void 0 ? void 0 : playback.removeMedia(index, connectionId, mediaId);
30
- }
31
- for (const { index, connectionId, mediaId } of values.added) {
32
- playback === null || playback === void 0 ? void 0 : playback.insertMedia(index, connectionId, mediaId);
33
- }
34
- break;
35
- case 'playbackTick':
36
- playback === null || playback === void 0 ? void 0 : playback.tick();
37
- break;
38
- case 'captureInit':
39
- capture = new Capture(values.sampleRate, LoadOdinWasm());
40
- values.workletPort.onmessage = (event) => onMessage(event);
41
- send(globalThis, [
42
- 'captureReady',
43
- {
44
- sampleBuffer: capture.samples,
45
- informationBuffer: capture.information,
46
- },
47
- ]);
48
- break;
49
- case 'captureSetVad':
50
- capture === null || capture === void 0 ? void 0 : capture.setVad(values);
51
- break;
52
- case 'captureSetMedias':
53
- capture === null || capture === void 0 ? void 0 : capture.setMedias(values.connections);
54
- break;
55
- case 'captureTick':
56
- capture === null || capture === void 0 ? void 0 : capture.tick();
57
- break;
58
- case 'close':
59
- playback === null || playback === void 0 ? void 0 : playback.close();
60
- capture === null || capture === void 0 ? void 0 : capture.close();
61
- self.close();
62
- break;
63
- }
64
- }
@@ -1,21 +0,0 @@
1
- /// <reference lib="webworker" />
2
- import type { OdinWasm } from '../../../lib/wasm';
3
- import { DecoderInformationBuffer, SampleBuffer } from '../buffers';
4
- export declare class Playback {
5
- readonly wasm: typeof OdinWasm;
6
- readonly sampleBuffer: SampleBuffer;
7
- readonly information: DecoderInformationBuffer;
8
- readonly medias: Map<number, {
9
- index: number;
10
- decoder: OdinWasm.Decoder;
11
- }>;
12
- readonly decoders: Uint32Array;
13
- largestIndex: number;
14
- id: number;
15
- constructor(wasm: typeof OdinWasm);
16
- close(): void;
17
- receivePacket(connectionId: number, packetBytes: Uint8Array): void;
18
- insertMedia(index: number, connectionId: number, mediaId: number): void;
19
- removeMedia(index: number, connectionId: number, mediaId: number): void;
20
- tick(): void;
21
- }
@@ -1,78 +0,0 @@
1
- /// <reference lib="WebWorker" />
2
- import { createDecoderInformationBuffer, createSampleBuffer, freeDecoderInformationBuffer, freeSampleBuffer, getSamples, setDecoderRmsDBFS, setHeader, } from '../buffers';
3
- import { mergeIds } from '../common';
4
- import { AdditionalPlaybackBlocks, MaxNumberOfDecoders } from '../config';
5
- import { malloc } from '../memory';
6
- import { Packet } from '../packet';
7
- export class Playback {
8
- constructor(wasm) {
9
- this.wasm = wasm;
10
- this.medias = new Map();
11
- this.largestIndex = -1;
12
- const numberOfBuffers = 2 + AdditionalPlaybackBlocks;
13
- this.sampleBuffer = createSampleBuffer(wasm, 48000, numberOfBuffers, true);
14
- this.sampleBuffer.samples.fill(0);
15
- const prefill = numberOfBuffers - 2;
16
- for (let i = 0; i < prefill; i++) {
17
- setHeader(this.sampleBuffer, i, { id: i });
18
- }
19
- this.id = prefill;
20
- this.decoders = malloc(this.wasm, 'u32', MaxNumberOfDecoders);
21
- this.information = createDecoderInformationBuffer(this.wasm, MaxNumberOfDecoders);
22
- }
23
- close() {
24
- freeSampleBuffer(this.wasm, this.sampleBuffer);
25
- freeDecoderInformationBuffer(this.wasm, this.information);
26
- for (const { decoder } of this.medias.values()) {
27
- decoder.delete();
28
- }
29
- }
30
- receivePacket(connectionId, packetBytes) {
31
- const packet = Packet.parse(packetBytes);
32
- if (packet.type === 'Failure') {
33
- console.error(`failed decoding audio packet; ${packet.reason}`);
34
- return;
35
- }
36
- for (const mediaId of packet.value.mediaIds) {
37
- const media = this.medias.get(mergeIds({ connectionId, mediaId }));
38
- if (media === undefined)
39
- continue;
40
- // the decoder keeps ownership of the payload
41
- const payload = malloc(this.wasm, 'u8', packet.value.payload.length);
42
- payload.set(packet.value.payload);
43
- media.decoder.push(packet.value.sequenceNumber, packet.value.timeStamp, packet.value.isEndOfSpurt, payload.byteOffset, payload.length);
44
- }
45
- }
46
- insertMedia(index, connectionId, mediaId) {
47
- const id = mergeIds({ connectionId, mediaId });
48
- const decoder = new this.wasm.Decoder();
49
- this.medias.set(id, { index, decoder });
50
- this.decoders[index] = decoder.$$.ptr;
51
- this.largestIndex = Math.max(this.largestIndex, index);
52
- }
53
- removeMedia(index, connectionId, mediaId) {
54
- const id = mergeIds({ connectionId, mediaId });
55
- const entry = this.medias.get(id);
56
- if (entry === undefined || entry.index !== index)
57
- return;
58
- this.medias.delete(id);
59
- setDecoderRmsDBFS(this.information, index, 0);
60
- this.decoders[index] = 0;
61
- entry.decoder.delete();
62
- if (index === this.largestIndex) {
63
- for (index = index - 1; index >= 0; index--) {
64
- if (this.decoders[index] !== 0)
65
- break;
66
- }
67
- this.largestIndex = index;
68
- }
69
- }
70
- tick() {
71
- const id = this.id++;
72
- const index = id % this.sampleBuffer.length;
73
- const hasAudio = this.wasm.pop_many(this.decoders.byteOffset, this.information.values.byteOffset, this.largestIndex + 1, getSamples(this.sampleBuffer, index).byteOffset);
74
- if (hasAudio) {
75
- setHeader(this.sampleBuffer, index, { id });
76
- }
77
- }
78
- }
@@ -1,28 +0,0 @@
1
- /// <reference lib="webworker" />
2
- import type { OdinWasm } from '../../../lib/wasm';
3
- import type { VadConfig } from '../common';
4
- import { EncoderInformationBuffer } from '../buffers';
5
- export declare class Capture {
6
- readonly sampleRate: number;
7
- readonly wasm: typeof OdinWasm;
8
- readonly encoder: OdinWasm.Encoder;
9
- readonly information: EncoderInformationBuffer;
10
- readonly inBuffer: Float32Array;
11
- readonly outBuffer: Uint8Array;
12
- sequenceNumber: number;
13
- timestamp: number;
14
- connections: Array<{
15
- id: number;
16
- mediaIds: number[];
17
- }>;
18
- active: boolean;
19
- constructor(sampleRate: number, wasm: typeof OdinWasm);
20
- setVad(config: VadConfig): void;
21
- setMedias(connections: Array<{
22
- id: number;
23
- mediaIds: number[];
24
- }>): void;
25
- setVolume(value: number): void;
26
- close(): void;
27
- tick(buffer: Float32Array): void;
28
- }