@4players/odin-plugin-web 1.0.0-alpha.7 → 1.0.0-alpha.9
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.
- package/lib/plugin/audioController.d.ts +9 -4
- package/lib/plugin/audioController.js +52 -6
- package/lib/plugin/config.d.ts +0 -1
- package/lib/plugin/config.js +0 -1
- package/lib/plugin/connectionPool.d.ts +0 -1
- package/lib/plugin/connectionPool.js +0 -1
- package/lib/plugin/index.d.ts +0 -1
- package/lib/plugin/index.js +0 -1
- package/lib/plugin/mainConnection.d.ts +0 -1
- package/lib/plugin/mainConnection.js +0 -1
- package/lib/plugin/roomConnection.d.ts +0 -1
- package/lib/plugin/roomConnection.js +10 -6
- package/lib/plugin/rpcConnection.d.ts +0 -1
- package/lib/plugin/rpcConnection.js +0 -1
- package/lib/plugin/token.d.ts +2 -1
- package/lib/plugin/token.js +12 -1
- package/lib/worker/buffers.d.ts +42 -0
- package/lib/worker/buffers.js +79 -0
- package/lib/worker/common.d.ts +44 -27
- package/lib/worker/common.js +2 -95
- package/lib/worker/config.d.ts +8 -0
- package/lib/worker/config.js +11 -0
- package/lib/worker/index.d.ts +1 -45
- package/lib/worker/index.js +1 -2
- package/lib/worker/memory.d.ts +9 -0
- package/lib/worker/memory.js +29 -0
- package/lib/worker/messages.d.ts +0 -80
- package/lib/worker/messages.js +0 -1
- package/lib/worker/packet.d.ts +11 -0
- package/lib/worker/packet.js +59 -0
- package/lib/worker/shared/capture.d.ts +28 -0
- package/lib/worker/shared/capture.js +63 -0
- package/lib/worker/shared/index.d.ts +3 -0
- package/lib/worker/shared/index.js +148 -0
- package/lib/worker/shared/messages.d.ts +67 -0
- package/lib/worker/shared/messages.js +64 -0
- package/lib/worker/shared/playback.d.ts +21 -0
- package/lib/worker/shared/playback.js +78 -0
- package/lib/worker/unshared/capture.d.ts +28 -0
- package/lib/worker/unshared/capture.js +66 -0
- package/lib/worker/unshared/index.d.ts +3 -0
- package/lib/worker/unshared/index.js +171 -0
- package/lib/worker/unshared/messages.d.ts +81 -0
- package/lib/worker/unshared/messages.js +80 -0
- package/lib/worker/unshared/playback.d.ts +23 -0
- package/lib/worker/unshared/playback.js +83 -0
- package/package.json +15 -11
- package/lib/wasm/index.js +0 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Backend, Strand } from '@4players/odin-common';
|
|
2
2
|
import { DeviceParameters } from '.';
|
|
3
|
-
import { CaptureSink, PlaybackId, PlaybackWorker } from '../worker';
|
|
4
3
|
import { RoomConnection } from './roomConnection';
|
|
4
|
+
import { CaptureSink, PlaybackId, PlaybackWorker } from '../worker/common';
|
|
5
5
|
export type Volume = Backend.Volume;
|
|
6
6
|
export type Activity = Backend.Activity;
|
|
7
7
|
export type CreateAudioPlaybackParameters = Backend.CreateAudioPlaybackParameters;
|
|
@@ -48,7 +48,13 @@ export declare class AudioController {
|
|
|
48
48
|
createAudioPlayback(parameters: CreateAudioPlaybackParameters): Promise<AudioPlayback>;
|
|
49
49
|
createAudioCapture(parameters: CreateAudioCaptureParameters): Promise<AudioCapture>;
|
|
50
50
|
enumerateDevices(): Promise<Device[]>;
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Requests audio and video browser permissions. Optionally, requests either audio or video permissions.
|
|
53
|
+
* @private
|
|
54
|
+
* @throws
|
|
55
|
+
*/
|
|
56
|
+
private _requestMediaPermissions;
|
|
57
|
+
playbackSetDevice(device?: Device): Promise<void>;
|
|
52
58
|
playbackSetGlobalVolume(value: Backend.Volume): void;
|
|
53
59
|
playbackStart(uid: string, id: GlobalMediaId): void;
|
|
54
60
|
playbackStop(uid: string, id: GlobalMediaId): void;
|
|
@@ -87,7 +93,7 @@ export declare class AudioCapture implements Backend.AudioCapture {
|
|
|
87
93
|
get vad(): Backend.VadConfig;
|
|
88
94
|
get apm(): Backend.ApmConfig;
|
|
89
95
|
get volume(): Backend.Volume;
|
|
90
|
-
get activity(): import("../worker").Activity;
|
|
96
|
+
get activity(): import("../worker/common").Activity;
|
|
91
97
|
get speechProbability(): number;
|
|
92
98
|
constructor(controller: AudioController, parameters: CreateAudioCaptureParameters);
|
|
93
99
|
start(room: RoomConnection, media: GlobalMediaId, uid: Backend.UID): void;
|
|
@@ -99,4 +105,3 @@ export declare class AudioCapture implements Backend.AudioCapture {
|
|
|
99
105
|
close(): void;
|
|
100
106
|
_UpdateMedias(): Promise<void>;
|
|
101
107
|
}
|
|
102
|
-
//# sourceMappingURL=audioController.d.ts.map
|
|
@@ -8,7 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { Strand, assert, failure, sleep, success, } from '@4players/odin-common';
|
|
11
|
-
import {
|
|
11
|
+
import { Silence, } from '../worker/common';
|
|
12
|
+
import { createCaptureWorker, createPlaybackWorker } from '../worker';
|
|
12
13
|
const defaultVad = {
|
|
13
14
|
voiceActivity: {
|
|
14
15
|
attackThreshold: 0.9,
|
|
@@ -76,6 +77,7 @@ export class AudioContextCollection {
|
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
}
|
|
80
|
+
let hasAudioPermissions = false;
|
|
79
81
|
export class AudioController {
|
|
80
82
|
create(audioContexts, sink) {
|
|
81
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -118,6 +120,7 @@ export class AudioController {
|
|
|
118
120
|
}
|
|
119
121
|
enumerateDevices() {
|
|
120
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
hasAudioPermissions = yield this._requestMediaPermissions();
|
|
121
124
|
const mediaDeviceInfos = yield navigator.mediaDevices.enumerateDevices();
|
|
122
125
|
const devices = [];
|
|
123
126
|
let outputDeviceIndex = 0;
|
|
@@ -145,6 +148,43 @@ export class AudioController {
|
|
|
145
148
|
return devices;
|
|
146
149
|
});
|
|
147
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Requests audio and video browser permissions. Optionally, requests either audio or video permissions.
|
|
153
|
+
* @private
|
|
154
|
+
* @throws
|
|
155
|
+
*/
|
|
156
|
+
_requestMediaPermissions() {
|
|
157
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
158
|
+
if (hasAudioPermissions)
|
|
159
|
+
return true;
|
|
160
|
+
const constraints = {};
|
|
161
|
+
constraints.audio = {
|
|
162
|
+
sampleRate: undefined,
|
|
163
|
+
deviceId: '',
|
|
164
|
+
autoGainControl: false,
|
|
165
|
+
noiseSuppression: false,
|
|
166
|
+
advanced: undefined,
|
|
167
|
+
aspectRatio: undefined,
|
|
168
|
+
echoCancellation: false,
|
|
169
|
+
channelCount: 0,
|
|
170
|
+
facingMode: undefined,
|
|
171
|
+
frameRate: 0,
|
|
172
|
+
};
|
|
173
|
+
console.log('Plugin _requestMediaPermissions: ', constraints);
|
|
174
|
+
try {
|
|
175
|
+
const ms = yield navigator.mediaDevices.getUserMedia(constraints);
|
|
176
|
+
ms === null || ms === void 0 ? void 0 : ms.getTracks().forEach((track) => {
|
|
177
|
+
track.stop();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
console.error(`Requesting permissions for ${'audio'} failed.`);
|
|
182
|
+
console.error(e);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
148
188
|
playbackSetDevice(device) {
|
|
149
189
|
return this.setPlaybackStrand.enqueue(() => __awaiter(this, void 0, void 0, function* () {
|
|
150
190
|
var _a;
|
|
@@ -155,13 +195,19 @@ export class AudioController {
|
|
|
155
195
|
let audioContext;
|
|
156
196
|
if (this.playbackWorker === undefined) {
|
|
157
197
|
audioContext = yield this.audioContexts.acquire(48000);
|
|
198
|
+
console.log('playbackSetDevice: this.audioContexts.acquire(48000)');
|
|
158
199
|
this.playbackWorker = yield createPlaybackWorker(audioContext);
|
|
159
200
|
this.playbackWorker.setGlobalVolume(this.globalVolume);
|
|
160
201
|
}
|
|
161
202
|
else {
|
|
203
|
+
console.log('this.playbackWorker.audioContext');
|
|
162
204
|
audioContext = this.playbackWorker.audioContext;
|
|
163
205
|
}
|
|
164
|
-
|
|
206
|
+
console.log('playbackSetDevice audioContext: ', audioContext);
|
|
207
|
+
if ((audioContext === null || audioContext === void 0 ? void 0 : audioContext.setSinkId) !== undefined &&
|
|
208
|
+
device &&
|
|
209
|
+
(audioContext === null || audioContext === void 0 ? void 0 : audioContext.state) === 'running') {
|
|
210
|
+
console.log('Browser audioContext.setSinkId');
|
|
165
211
|
yield audioContext.setSinkId(deviceId);
|
|
166
212
|
}
|
|
167
213
|
}));
|
|
@@ -197,8 +243,8 @@ export class AudioController {
|
|
|
197
243
|
var _a, _b;
|
|
198
244
|
const entry = this.playbacks.get(uid);
|
|
199
245
|
if ((entry === null || entry === void 0 ? void 0 : entry.id) === undefined)
|
|
200
|
-
return
|
|
201
|
-
return (_b = (_a = this.playbackWorker) === null || _a === void 0 ? void 0 : _a.getActivity(entry.id)) !== null && _b !== void 0 ? _b :
|
|
246
|
+
return Silence;
|
|
247
|
+
return (_b = (_a = this.playbackWorker) === null || _a === void 0 ? void 0 : _a.getActivity(entry.id)) !== null && _b !== void 0 ? _b : Silence;
|
|
202
248
|
}
|
|
203
249
|
playbackSetVolume(uid, volume) {
|
|
204
250
|
var _a;
|
|
@@ -284,7 +330,7 @@ export class AudioCapture {
|
|
|
284
330
|
}
|
|
285
331
|
get activity() {
|
|
286
332
|
var _a, _b;
|
|
287
|
-
return (_b = (_a = this._Capture) === null || _a === void 0 ? void 0 : _a.worker.activity) !== null && _b !== void 0 ? _b :
|
|
333
|
+
return (_b = (_a = this._Capture) === null || _a === void 0 ? void 0 : _a.worker.activity) !== null && _b !== void 0 ? _b : Silence;
|
|
288
334
|
}
|
|
289
335
|
get speechProbability() {
|
|
290
336
|
var _a, _b;
|
|
@@ -429,6 +475,7 @@ function openCaptureDevice(controller, parameters, apm) {
|
|
|
429
475
|
]);
|
|
430
476
|
if (result === 'timeout')
|
|
431
477
|
return failure('getUserMedia; timeout');
|
|
478
|
+
hasAudioPermissions = true;
|
|
432
479
|
stream = result;
|
|
433
480
|
}
|
|
434
481
|
catch (reason) {
|
|
@@ -439,4 +486,3 @@ function openCaptureDevice(controller, parameters, apm) {
|
|
|
439
486
|
return success(context.createMediaStreamSource(stream));
|
|
440
487
|
});
|
|
441
488
|
}
|
|
442
|
-
//# sourceMappingURL=audioController.js.map
|
package/lib/plugin/config.d.ts
CHANGED
package/lib/plugin/config.js
CHANGED
package/lib/plugin/index.d.ts
CHANGED
package/lib/plugin/index.js
CHANGED
|
@@ -122,20 +122,25 @@ export class RoomConnection {
|
|
|
122
122
|
}
|
|
123
123
|
_ConnectToServer() {
|
|
124
124
|
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
-
|
|
125
|
+
// for now strip upstream wrappers in the token, because it not supported in web
|
|
126
|
+
let token = this._Token;
|
|
127
|
+
while (token.upstream !== undefined) {
|
|
128
|
+
token = token.upstream;
|
|
129
|
+
}
|
|
130
|
+
if (!token.hasAudience('sfu') || token.address === undefined) {
|
|
126
131
|
return success('continue');
|
|
127
132
|
}
|
|
128
|
-
this._ChangeStatus('Joining', `connecting to ${
|
|
133
|
+
this._ChangeStatus('Joining', `connecting to ${token.address}`);
|
|
129
134
|
// are we already connected to the server?
|
|
130
135
|
if (this._MainConnection === undefined ||
|
|
131
136
|
this._MainConnection.closed ||
|
|
132
|
-
this._MainConnection.url !==
|
|
137
|
+
this._MainConnection.url !== token.address) {
|
|
133
138
|
// no? release the not fitting connection
|
|
134
139
|
if (this._MainConnection) {
|
|
135
140
|
this.connectionPool.releaseConnection(this._MainConnection);
|
|
136
141
|
}
|
|
137
142
|
// connect to the right server
|
|
138
|
-
const mainConnection = yield this.connectionPool.acquireConnection(
|
|
143
|
+
const mainConnection = yield this.connectionPool.acquireConnection(token.address, this._Close.signal);
|
|
139
144
|
if (mainConnection === 'closed')
|
|
140
145
|
return failure('connection pool closed'); // connection pool is closed
|
|
141
146
|
if (mainConnection.type === 'Failure') {
|
|
@@ -147,7 +152,7 @@ export class RoomConnection {
|
|
|
147
152
|
// join room
|
|
148
153
|
const result = yield Promise.race([
|
|
149
154
|
Promise.all([
|
|
150
|
-
this._MainConnection.joinRoom(
|
|
155
|
+
this._MainConnection.joinRoom(token, this.roomId, this.userData, this.position),
|
|
151
156
|
]),
|
|
152
157
|
sleep(ConnectTimeout, 'timeout'),
|
|
153
158
|
this._Closed,
|
|
@@ -296,4 +301,3 @@ function contactGateway(gateway, token, signal) {
|
|
|
296
301
|
}
|
|
297
302
|
});
|
|
298
303
|
}
|
|
299
|
-
//# sourceMappingURL=roomConnection.js.map
|
|
@@ -46,4 +46,3 @@ export declare class TypedRpcConnection<C extends Commands, E extends Events> ex
|
|
|
46
46
|
notify<Name extends Extract<keyof C, string>>(name: Name, properties: z.infer<C[Name]['request']>): void;
|
|
47
47
|
recv(): Promise<RealizedEvents<E> | 'closed'>;
|
|
48
48
|
}
|
|
49
|
-
//# sourceMappingURL=rpcConnection.d.ts.map
|
package/lib/plugin/token.d.ts
CHANGED
|
@@ -6,11 +6,12 @@ export declare class Token {
|
|
|
6
6
|
readonly claims: TokenClaims;
|
|
7
7
|
static parse(token: string): Result<Token>;
|
|
8
8
|
private readonly _Address;
|
|
9
|
+
private readonly _Upstream;
|
|
9
10
|
protected constructor(text: string, claims: TokenClaims);
|
|
10
11
|
get timeLeft(): number;
|
|
11
12
|
get address(): URL | undefined;
|
|
13
|
+
get upstream(): Token | undefined;
|
|
12
14
|
get defaultRoomId(): string | undefined;
|
|
13
15
|
hasAudience(audience: z.infer<typeof TokenAudienceSchema>): boolean;
|
|
14
16
|
toString(): string;
|
|
15
17
|
}
|
|
16
|
-
//# sourceMappingURL=token.d.ts.map
|
package/lib/plugin/token.js
CHANGED
|
@@ -33,6 +33,15 @@ export class Token {
|
|
|
33
33
|
console.error(`address in token(${address}) can not be parsed; ${error}`);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
if (claims.ups !== undefined) {
|
|
37
|
+
const upstream = Token.parse(claims.ups);
|
|
38
|
+
if (upstream.type === 'Success') {
|
|
39
|
+
this._Upstream = upstream.value;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.error(`upstream in token can not be parsed; ${upstream.reason}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
36
45
|
}
|
|
37
46
|
get timeLeft() {
|
|
38
47
|
if (this.claims.exp === undefined)
|
|
@@ -42,6 +51,9 @@ export class Token {
|
|
|
42
51
|
get address() {
|
|
43
52
|
return this._Address;
|
|
44
53
|
}
|
|
54
|
+
get upstream() {
|
|
55
|
+
return this._Upstream;
|
|
56
|
+
}
|
|
45
57
|
get defaultRoomId() {
|
|
46
58
|
if (Array.isArray(this.claims.rid)) {
|
|
47
59
|
return this.claims.rid.length === 1 ? this.claims.rid[0] : undefined;
|
|
@@ -64,4 +76,3 @@ export class Token {
|
|
|
64
76
|
return this.text;
|
|
65
77
|
}
|
|
66
78
|
}
|
|
67
|
-
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { OdinWasm } from '../../lib/wasm';
|
|
2
|
+
export interface SampleBuffer {
|
|
3
|
+
readonly headers: Int32Array;
|
|
4
|
+
readonly samples: Float32Array;
|
|
5
|
+
readonly length: number;
|
|
6
|
+
readonly sampleRate: number;
|
|
7
|
+
readonly stereo: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface SampleBufferHeader {
|
|
10
|
+
id: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function createSampleBuffer(wasm: typeof OdinWasm, sampleRate: number, length: number, stereo: boolean): SampleBuffer;
|
|
13
|
+
export declare function freeSampleBuffer(wasm: typeof OdinWasm, buffer: SampleBuffer): void;
|
|
14
|
+
export declare function samplesPerEntry(buffer: {
|
|
15
|
+
sampleRate: number;
|
|
16
|
+
stereo: boolean;
|
|
17
|
+
}): number;
|
|
18
|
+
export declare function getSamples(buffer: SampleBuffer, index: number): Float32Array;
|
|
19
|
+
export declare function getHeader(buffer: SampleBuffer, index: number): SampleBufferHeader;
|
|
20
|
+
export declare function setHeader(buffer: SampleBuffer, index: number, header: SampleBufferHeader): void;
|
|
21
|
+
export interface DecoderInformationBuffer {
|
|
22
|
+
readonly values: Float32Array;
|
|
23
|
+
readonly length: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function createDecoderInformationBuffer(wasm: typeof OdinWasm, length: number): DecoderInformationBuffer;
|
|
26
|
+
export declare function freeDecoderInformationBuffer(wasm: typeof OdinWasm, buffer: DecoderInformationBuffer): void;
|
|
27
|
+
export declare function getGlobalDecoderVolume(buffer: DecoderInformationBuffer): number;
|
|
28
|
+
export declare function setGlobalDecoderVolume(buffer: DecoderInformationBuffer, value: number): void;
|
|
29
|
+
export declare function getDecoderRmsDBFS(buffer: DecoderInformationBuffer, index: number): number;
|
|
30
|
+
export declare function setDecoderRmsDBFS(buffer: DecoderInformationBuffer, index: number, value: number): void;
|
|
31
|
+
export declare function getDecoderVolume(buffer: DecoderInformationBuffer, index: number): number;
|
|
32
|
+
export declare function setDecoderVolume(buffer: DecoderInformationBuffer, index: number, value: number): void;
|
|
33
|
+
export interface EncoderInformationBuffer {
|
|
34
|
+
readonly values: Float32Array;
|
|
35
|
+
}
|
|
36
|
+
export declare function createEncoderInformationBuffer(wasm: typeof OdinWasm): EncoderInformationBuffer;
|
|
37
|
+
export declare function freeEncoderInformationBuffer(wasm: typeof OdinWasm, buffer: EncoderInformationBuffer): void;
|
|
38
|
+
export declare function getEncoderActive(buffer: EncoderInformationBuffer): boolean;
|
|
39
|
+
export declare function getEncoderSpeechProbability(buffer: EncoderInformationBuffer): number;
|
|
40
|
+
export declare function getEncoderRmsDBFS(buffer: EncoderInformationBuffer): number;
|
|
41
|
+
export declare function getEncoderVolume(buffer: EncoderInformationBuffer): number;
|
|
42
|
+
export declare function setEncoderVolume(buffer: EncoderInformationBuffer, value: number): number;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { free, malloc } from './memory';
|
|
2
|
+
export function createSampleBuffer(wasm, sampleRate, length, stereo) {
|
|
3
|
+
return {
|
|
4
|
+
headers: malloc(wasm, 'i32', length),
|
|
5
|
+
samples: malloc(wasm, 'f32', length * samplesPerEntry({ sampleRate, stereo })),
|
|
6
|
+
length,
|
|
7
|
+
sampleRate,
|
|
8
|
+
stereo,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function freeSampleBuffer(wasm, buffer) {
|
|
12
|
+
free(wasm, buffer.headers);
|
|
13
|
+
free(wasm, buffer.samples);
|
|
14
|
+
}
|
|
15
|
+
export function samplesPerEntry(buffer) {
|
|
16
|
+
return buffer.sampleRate * 0.02 * (buffer.stereo ? 2 : 1);
|
|
17
|
+
}
|
|
18
|
+
export function getSamples(buffer, index) {
|
|
19
|
+
const size = samplesPerEntry(buffer);
|
|
20
|
+
const begin = size * index;
|
|
21
|
+
const end = begin + size;
|
|
22
|
+
return buffer.samples.subarray(begin, end);
|
|
23
|
+
}
|
|
24
|
+
export function getHeader(buffer, index) {
|
|
25
|
+
return { id: buffer.headers[index] };
|
|
26
|
+
}
|
|
27
|
+
export function setHeader(buffer, index, header) {
|
|
28
|
+
buffer.headers[index] = header.id;
|
|
29
|
+
}
|
|
30
|
+
export function createDecoderInformationBuffer(wasm, length) {
|
|
31
|
+
return {
|
|
32
|
+
values: malloc(wasm, 'f32', 1 + length * 2),
|
|
33
|
+
length,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function freeDecoderInformationBuffer(wasm, buffer) {
|
|
37
|
+
free(wasm, buffer.values);
|
|
38
|
+
}
|
|
39
|
+
export function getGlobalDecoderVolume(buffer) {
|
|
40
|
+
return buffer.values[0];
|
|
41
|
+
}
|
|
42
|
+
export function setGlobalDecoderVolume(buffer, value) {
|
|
43
|
+
buffer.values[0] = value;
|
|
44
|
+
}
|
|
45
|
+
export function getDecoderRmsDBFS(buffer, index) {
|
|
46
|
+
return buffer.values[1 + index * 2];
|
|
47
|
+
}
|
|
48
|
+
export function setDecoderRmsDBFS(buffer, index, value) {
|
|
49
|
+
buffer.values[1 + index * 2] = value;
|
|
50
|
+
}
|
|
51
|
+
export function getDecoderVolume(buffer, index) {
|
|
52
|
+
return buffer.values[1 + index * 2 + 1];
|
|
53
|
+
}
|
|
54
|
+
export function setDecoderVolume(buffer, index, value) {
|
|
55
|
+
buffer.values[1 + index * 2 + 1] = value;
|
|
56
|
+
}
|
|
57
|
+
export function createEncoderInformationBuffer(wasm) {
|
|
58
|
+
return {
|
|
59
|
+
values: malloc(wasm, 'f32', 4),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function freeEncoderInformationBuffer(wasm, buffer) {
|
|
63
|
+
free(wasm, buffer.values);
|
|
64
|
+
}
|
|
65
|
+
export function getEncoderActive(buffer) {
|
|
66
|
+
return buffer.values[0] !== 0;
|
|
67
|
+
}
|
|
68
|
+
export function getEncoderSpeechProbability(buffer) {
|
|
69
|
+
return buffer.values[1];
|
|
70
|
+
}
|
|
71
|
+
export function getEncoderRmsDBFS(buffer) {
|
|
72
|
+
return buffer.values[2];
|
|
73
|
+
}
|
|
74
|
+
export function getEncoderVolume(buffer) {
|
|
75
|
+
return buffer.values[3];
|
|
76
|
+
}
|
|
77
|
+
export function setEncoderVolume(buffer, value) {
|
|
78
|
+
return (buffer.values[3] = value);
|
|
79
|
+
}
|
package/lib/worker/common.d.ts
CHANGED
|
@@ -1,28 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare const
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
readonly
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
export interface Activity {
|
|
2
|
+
isSilent: boolean;
|
|
3
|
+
rmsDBFS: number;
|
|
4
|
+
}
|
|
5
|
+
export declare const Silence: Activity;
|
|
6
|
+
export interface VadConfig {
|
|
7
|
+
volumeGate?: {
|
|
8
|
+
attackThreshold: number;
|
|
9
|
+
releaseThreshold: number;
|
|
10
|
+
};
|
|
11
|
+
voiceActivity?: {
|
|
12
|
+
attackThreshold: number;
|
|
13
|
+
releaseThreshold: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export type CaptureSink = (connectionId: number, packet: Uint8Array) => void;
|
|
17
|
+
export interface CaptureWorker {
|
|
18
|
+
readonly worklet: AudioWorkletNode;
|
|
19
|
+
readonly worker: Worker;
|
|
20
|
+
get context(): BaseAudioContext;
|
|
21
|
+
get activity(): Activity;
|
|
22
|
+
get speechProbability(): number;
|
|
23
|
+
setMedias(connections: Array<{
|
|
24
|
+
id: number;
|
|
25
|
+
mediaIds: number[];
|
|
26
|
+
}>): void;
|
|
27
|
+
setVolume(value: number): void;
|
|
28
|
+
setVad(config: VadConfig): void;
|
|
29
|
+
close(): void;
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
export interface PlaybackWorker {
|
|
32
|
+
readonly audioContext: AudioContext;
|
|
33
|
+
receivePacket(connectionId: number, packet: Uint8Array): void;
|
|
34
|
+
addMedias(connectionId: number, mediaIds: number[]): void;
|
|
35
|
+
removeMedias(connectionId: number, mediaIds: number[]): void;
|
|
36
|
+
getActivity(id: PlaybackId): Activity | undefined;
|
|
37
|
+
setGlobalVolume(value: number): void;
|
|
38
|
+
setVolume(id: PlaybackId, value: number): void;
|
|
39
|
+
close(): void;
|
|
40
|
+
}
|
|
41
|
+
export interface PlaybackId {
|
|
42
|
+
connectionId: number;
|
|
43
|
+
mediaId: number;
|
|
44
|
+
}
|
|
45
|
+
export declare function mergeIds(id: PlaybackId): number;
|
package/lib/worker/common.js
CHANGED
|
@@ -1,100 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import * as msgpack from '@msgpack/msgpack';
|
|
4
|
-
export const PlaybackPreload = 3;
|
|
5
|
-
export const DefaultRefreshRate = 250;
|
|
6
|
-
export const VadPreload = 3;
|
|
7
|
-
export const MaxNumberOfDecoders = 512;
|
|
8
|
-
export const MinDBFs = -758.596;
|
|
9
|
-
export function malloc(wasm, element, length) {
|
|
10
|
-
let heap;
|
|
11
|
-
switch (element) {
|
|
12
|
-
case 'f32':
|
|
13
|
-
heap = wasm.HEAPF32;
|
|
14
|
-
break;
|
|
15
|
-
case 'u32':
|
|
16
|
-
heap = wasm.HEAPU32;
|
|
17
|
-
break;
|
|
18
|
-
case 'i32':
|
|
19
|
-
heap = wasm.HEAP32;
|
|
20
|
-
break;
|
|
21
|
-
case 'u8':
|
|
22
|
-
heap = wasm.HEAPU8;
|
|
23
|
-
break;
|
|
24
|
-
default:
|
|
25
|
-
throw new Error(`allocating ${element} is not supported`);
|
|
26
|
-
}
|
|
27
|
-
const pointer = wasm._malloc(length * heap.BYTES_PER_ELEMENT);
|
|
28
|
-
if (pointer === 0 || pointer % heap.BYTES_PER_ELEMENT !== 0) {
|
|
29
|
-
throw new Error(`failed allocating a ${length} ${element} array`);
|
|
30
|
-
}
|
|
31
|
-
const start = pointer / heap.BYTES_PER_ELEMENT;
|
|
32
|
-
return heap.subarray(start, start + length);
|
|
33
|
-
}
|
|
34
|
-
export function free(wasm, array) {
|
|
35
|
-
wasm._free(array.byteOffset);
|
|
36
|
-
}
|
|
1
|
+
import { MinDBFs } from './config';
|
|
2
|
+
export const Silence = { isSilent: true, rmsDBFS: MinDBFs };
|
|
37
3
|
export function mergeIds(id) {
|
|
38
4
|
// connectionId is 21 Bits.
|
|
39
5
|
// mediaId is 32 Bits
|
|
40
6
|
return id.connectionId * 4294967296 + id.mediaId;
|
|
41
7
|
}
|
|
42
|
-
export class Packet {
|
|
43
|
-
static parse(bytes) {
|
|
44
|
-
let parsed;
|
|
45
|
-
try {
|
|
46
|
-
parsed = msgpack.decode(bytes);
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
return failure('not valid msgpack');
|
|
50
|
-
}
|
|
51
|
-
if (!Array.isArray(parsed))
|
|
52
|
-
return failure('container must be an array');
|
|
53
|
-
if (parsed.length < 6)
|
|
54
|
-
return failure('missing fields');
|
|
55
|
-
if (parsed[0] !== 1)
|
|
56
|
-
return failure('unknown type');
|
|
57
|
-
if (!Array.isArray(parsed[1]))
|
|
58
|
-
return failure('media ids must be an array');
|
|
59
|
-
if (!parsed[1].every((entry) => typeof entry === 'number')) {
|
|
60
|
-
return failure('media ids must be numbers');
|
|
61
|
-
}
|
|
62
|
-
if (typeof parsed[2] !== 'number') {
|
|
63
|
-
return failure('sequence number must be a number');
|
|
64
|
-
}
|
|
65
|
-
if (typeof parsed[3] !== 'number') {
|
|
66
|
-
return failure('timestamp must be a number');
|
|
67
|
-
}
|
|
68
|
-
if (typeof parsed[4] !== 'number')
|
|
69
|
-
return failure('flags must be a number');
|
|
70
|
-
const mediaIds = parsed[1];
|
|
71
|
-
const sequenceNumber = parsed[2] >>> 0;
|
|
72
|
-
const timeStamp = parsed[3] >>> 0;
|
|
73
|
-
const flags = parsed[4];
|
|
74
|
-
const isEndOfSpurt = (flags & 0x01) !== 0;
|
|
75
|
-
const payload = parsed[parsed.length - 1];
|
|
76
|
-
if (!(payload instanceof Uint8Array)) {
|
|
77
|
-
return failure('payload must be bytes');
|
|
78
|
-
}
|
|
79
|
-
return success(new Packet(mediaIds, sequenceNumber, timeStamp, isEndOfSpurt, payload));
|
|
80
|
-
}
|
|
81
|
-
constructor(mediaIds, sequenceNumber, timeStamp, isEndOfSpurt, payload) {
|
|
82
|
-
this.mediaIds = mediaIds;
|
|
83
|
-
this.sequenceNumber = sequenceNumber;
|
|
84
|
-
this.timeStamp = timeStamp;
|
|
85
|
-
this.isEndOfSpurt = isEndOfSpurt;
|
|
86
|
-
this.payload = payload;
|
|
87
|
-
}
|
|
88
|
-
toBytes() {
|
|
89
|
-
const flags = Number(this.isEndOfSpurt);
|
|
90
|
-
return msgpack.encode([
|
|
91
|
-
1,
|
|
92
|
-
this.mediaIds,
|
|
93
|
-
this.sequenceNumber >>> 0,
|
|
94
|
-
this.timeStamp >>> 0,
|
|
95
|
-
flags,
|
|
96
|
-
this.payload,
|
|
97
|
-
]);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const AdditionalPlaybackBlocks = 3;
|
|
2
|
+
export declare const AdditionalCaptureBlocks = 3;
|
|
3
|
+
export declare const PlaybackPreload = 3;
|
|
4
|
+
export declare const DefaultRefreshRate = 250;
|
|
5
|
+
export declare const VadPreload = 3;
|
|
6
|
+
export declare const MaxNumberOfDecoders = 512;
|
|
7
|
+
export declare const RenderQuantumSize = 128;
|
|
8
|
+
export declare const MinDBFs = -758.596;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// shared
|
|
2
|
+
export const AdditionalPlaybackBlocks = 3;
|
|
3
|
+
export const AdditionalCaptureBlocks = 3;
|
|
4
|
+
// unshared
|
|
5
|
+
export const PlaybackPreload = 3;
|
|
6
|
+
export const DefaultRefreshRate = 250;
|
|
7
|
+
// both
|
|
8
|
+
export const VadPreload = 3;
|
|
9
|
+
export const MaxNumberOfDecoders = 512;
|
|
10
|
+
export const RenderQuantumSize = 128;
|
|
11
|
+
export const MinDBFs = -758.596;
|