@4players/odin-plugin-web 1.0.0-alpha.1 → 1.0.0-alpha.11
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/README.md +18 -18
- package/{backend/lib → lib/plugin}/audioController.d.ts +11 -6
- package/{backend/lib → lib/plugin}/audioController.js +100 -19
- package/{backend/lib → lib/plugin}/config.d.ts +0 -1
- package/{backend/lib → lib/plugin}/config.js +0 -1
- package/{backend/lib → lib/plugin}/connectionPool.d.ts +0 -1
- package/{backend/lib → lib/plugin}/connectionPool.js +0 -1
- package/{backend/lib → lib/plugin}/index.d.ts +1 -2
- package/{backend/lib → lib/plugin}/index.js +3 -2
- package/{backend/lib → lib/plugin}/mainConnection.d.ts +0 -1
- package/{backend/lib → lib/plugin}/mainConnection.js +0 -1
- package/{backend/lib → lib/plugin}/roomConnection.d.ts +0 -1
- package/{backend/lib → lib/plugin}/roomConnection.js +10 -6
- package/{backend/lib → lib/plugin}/rpcConnection.d.ts +0 -1
- package/{backend/lib → lib/plugin}/rpcConnection.js +0 -1
- package/{backend/lib → lib/plugin}/token.d.ts +2 -1
- package/{backend/lib → lib/plugin}/token.js +12 -1
- package/lib/worker/buffers.d.ts +42 -0
- package/lib/worker/buffers.js +79 -0
- package/{worker/lib/index.d.ts → lib/worker/common.d.ts} +7 -8
- package/lib/worker/common.js +7 -0
- package/lib/worker/config.d.ts +8 -0
- package/lib/worker/config.js +11 -0
- package/lib/worker/index.d.ts +3 -0
- package/lib/worker/index.js +1 -0
- package/lib/worker/memory.d.ts +9 -0
- package/lib/worker/memory.js +29 -0
- package/lib/worker/messages.d.ts +14 -0
- package/lib/worker/messages.js +15 -0
- 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/{worker/lib → lib/worker/unshared}/messages.d.ts +3 -15
- 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 +19 -16
- package/backend/lib/audioController.d.ts.map +0 -1
- package/backend/lib/audioController.js.map +0 -1
- package/backend/lib/config.d.ts.map +0 -1
- package/backend/lib/config.js.map +0 -1
- package/backend/lib/connectionPool.d.ts.map +0 -1
- package/backend/lib/connectionPool.js.map +0 -1
- package/backend/lib/index.d.ts.map +0 -1
- package/backend/lib/index.js.map +0 -1
- package/backend/lib/mainConnection.d.ts.map +0 -1
- package/backend/lib/mainConnection.js.map +0 -1
- package/backend/lib/roomConnection.d.ts.map +0 -1
- package/backend/lib/roomConnection.js.map +0 -1
- package/backend/lib/rpcConnection.d.ts.map +0 -1
- package/backend/lib/rpcConnection.js.map +0 -1
- package/backend/lib/token.d.ts.map +0 -1
- package/backend/lib/token.js.map +0 -1
- package/backend/package.json +0 -13
- package/wasm/lib/index.js +0 -19
- package/wasm/package.json +0 -14
- package/worker/lib/common.d.ts +0 -27
- package/worker/lib/index.js +0 -2
- package/worker/package.json +0 -13
- /package/{wasm/lib → lib/wasm}/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
+
# @4players/odin-plugin-web
|
|
1
2
|
|
|
2
|
-
|
|
3
|
+
[][npm-badge-url]
|
|
4
|
+
[][license-url]
|
|
5
|
+
[][npm-badge-url]
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
A backend plugin for the [@4players/odin](https://www.npmjs.com/package/@4players/odin) SDK package supporting web browsers.
|
|
5
8
|
|
|
6
|
-
##
|
|
9
|
+
## Troubleshooting
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
Contact us through the listed methods below to receive answers to your questions and learn more about ODIN.
|
|
9
12
|
|
|
10
|
-
###
|
|
13
|
+
### Discord
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
asdf plugin add nodejs
|
|
14
|
-
asdf plugin add emsdk
|
|
15
|
-
asdf install
|
|
16
|
-
```
|
|
15
|
+
Join our official Discord server to chat with us directly and become a part of the 4Players ODIN community.
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
[](https://4np.de/discord)
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
npm run build
|
|
22
|
-
```
|
|
19
|
+
### Twitter
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
Have a quick question? Tweet us at [@ODIN4Players](https://twitter.com/ODIN4Players) and we’ll help you resolve any issues.
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
### Email
|
|
24
|
+
|
|
25
|
+
Don’t use Discord or Twitter? Send us an [email](mailto:odin@4players.io) and we’ll get back to you as soon as possible.
|
|
26
|
+
|
|
27
|
+
[npm-badge-url]: https://www.npmjs.com/package/@4players/odin-plugin-web
|
|
28
|
+
[license-url]: https://github.com/4Players/odin-sdk-web/blob/master/LICENSE
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Backend, Strand } from '@4players/odin-common';
|
|
2
2
|
import { DeviceParameters } from '.';
|
|
3
|
-
import { CaptureSink, PlaybackId, PlaybackWorker } from '@4players/odin-plugin-web-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;
|
|
@@ -60,10 +66,10 @@ export declare class AudioController {
|
|
|
60
66
|
}
|
|
61
67
|
export declare class Device implements Backend.Device {
|
|
62
68
|
readonly device: MediaDeviceInfo;
|
|
63
|
-
|
|
69
|
+
readonly isDefault: boolean;
|
|
70
|
+
constructor(device: MediaDeviceInfo, isDefault?: boolean);
|
|
64
71
|
get type(): "AudioPlayback" | "AudioCapture";
|
|
65
72
|
get name(): string;
|
|
66
|
-
get isDefault(): boolean;
|
|
67
73
|
}
|
|
68
74
|
export declare class AudioPlayback implements Backend.AudioPlayback {
|
|
69
75
|
readonly controller: AudioController;
|
|
@@ -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("
|
|
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,28 +120,95 @@ export class AudioController {
|
|
|
118
120
|
}
|
|
119
121
|
enumerateDevices() {
|
|
120
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
hasAudioPermissions = yield this._requestMediaPermissions();
|
|
124
|
+
const mediaDeviceInfos = yield navigator.mediaDevices.enumerateDevices();
|
|
125
|
+
const devices = [];
|
|
126
|
+
let outputDeviceIndex = 0;
|
|
127
|
+
let inputDeviceIndex = 0;
|
|
128
|
+
for (const mediaDeviceInfo of mediaDeviceInfos) {
|
|
129
|
+
if (mediaDeviceInfo.kind === 'audioinput') {
|
|
130
|
+
if (inputDeviceIndex === 0) {
|
|
131
|
+
devices.push(new Device(mediaDeviceInfo, true));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
devices.push(new Device(mediaDeviceInfo, false));
|
|
135
|
+
}
|
|
136
|
+
inputDeviceIndex++;
|
|
137
|
+
}
|
|
138
|
+
if (mediaDeviceInfo.kind === 'audiooutput') {
|
|
139
|
+
if (outputDeviceIndex === 0) {
|
|
140
|
+
devices.push(new Device(mediaDeviceInfo, true));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
devices.push(new Device(mediaDeviceInfo, false));
|
|
144
|
+
}
|
|
145
|
+
outputDeviceIndex++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return devices;
|
|
149
|
+
});
|
|
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
|
+
ms.removeTrack(track);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
console.error(`Requesting permissions for ${'audio'} failed.`);
|
|
183
|
+
console.error(e);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
125
187
|
});
|
|
126
188
|
}
|
|
127
189
|
playbackSetDevice(device) {
|
|
128
190
|
return this.setPlaybackStrand.enqueue(() => __awaiter(this, void 0, void 0, function* () {
|
|
129
191
|
var _a;
|
|
130
|
-
|
|
192
|
+
let deviceId = (_a = device === null || device === void 0 ? void 0 : device.device.deviceId) !== null && _a !== void 0 ? _a : '';
|
|
193
|
+
if (deviceId === 'default') {
|
|
194
|
+
deviceId = '';
|
|
195
|
+
}
|
|
131
196
|
let audioContext;
|
|
132
197
|
if (this.playbackWorker === undefined) {
|
|
133
198
|
audioContext = yield this.audioContexts.acquire(48000);
|
|
199
|
+
console.log('playbackSetDevice: this.audioContexts.acquire(48000)');
|
|
134
200
|
this.playbackWorker = yield createPlaybackWorker(audioContext);
|
|
135
201
|
this.playbackWorker.setGlobalVolume(this.globalVolume);
|
|
136
202
|
}
|
|
137
203
|
else {
|
|
204
|
+
console.log('this.playbackWorker.audioContext');
|
|
138
205
|
audioContext = this.playbackWorker.audioContext;
|
|
139
206
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
207
|
+
console.log('playbackSetDevice audioContext: ', audioContext);
|
|
208
|
+
if ((audioContext === null || audioContext === void 0 ? void 0 : audioContext.setSinkId) !== undefined &&
|
|
209
|
+
device &&
|
|
210
|
+
(audioContext === null || audioContext === void 0 ? void 0 : audioContext.state) === 'running') {
|
|
211
|
+
console.log('Browser audioContext.setSinkId');
|
|
143
212
|
yield audioContext.setSinkId(deviceId);
|
|
144
213
|
}
|
|
145
214
|
}));
|
|
@@ -175,8 +244,8 @@ export class AudioController {
|
|
|
175
244
|
var _a, _b;
|
|
176
245
|
const entry = this.playbacks.get(uid);
|
|
177
246
|
if ((entry === null || entry === void 0 ? void 0 : entry.id) === undefined)
|
|
178
|
-
return
|
|
179
|
-
return (_b = (_a = this.playbackWorker) === null || _a === void 0 ? void 0 : _a.getActivity(entry.id)) !== null && _b !== void 0 ? _b :
|
|
247
|
+
return Silence;
|
|
248
|
+
return (_b = (_a = this.playbackWorker) === null || _a === void 0 ? void 0 : _a.getActivity(entry.id)) !== null && _b !== void 0 ? _b : Silence;
|
|
180
249
|
}
|
|
181
250
|
playbackSetVolume(uid, volume) {
|
|
182
251
|
var _a;
|
|
@@ -208,8 +277,9 @@ export class AudioController {
|
|
|
208
277
|
}
|
|
209
278
|
}
|
|
210
279
|
export class Device {
|
|
211
|
-
constructor(device) {
|
|
280
|
+
constructor(device, isDefault = false) {
|
|
212
281
|
this.device = device;
|
|
282
|
+
this.isDefault = isDefault;
|
|
213
283
|
}
|
|
214
284
|
get type() {
|
|
215
285
|
switch (this.device.kind) {
|
|
@@ -224,9 +294,6 @@ export class Device {
|
|
|
224
294
|
get name() {
|
|
225
295
|
return this.device.label;
|
|
226
296
|
}
|
|
227
|
-
get isDefault() {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
297
|
}
|
|
231
298
|
export class AudioPlayback {
|
|
232
299
|
get volume() {
|
|
@@ -264,7 +331,7 @@ export class AudioCapture {
|
|
|
264
331
|
}
|
|
265
332
|
get activity() {
|
|
266
333
|
var _a, _b;
|
|
267
|
-
return (_b = (_a = this._Capture) === null || _a === void 0 ? void 0 : _a.worker.activity) !== null && _b !== void 0 ? _b :
|
|
334
|
+
return (_b = (_a = this._Capture) === null || _a === void 0 ? void 0 : _a.worker.activity) !== null && _b !== void 0 ? _b : Silence;
|
|
268
335
|
}
|
|
269
336
|
get speechProbability() {
|
|
270
337
|
var _a, _b;
|
|
@@ -362,14 +429,22 @@ export class AudioCapture {
|
|
|
362
429
|
});
|
|
363
430
|
}
|
|
364
431
|
setVolume(value) {
|
|
432
|
+
var _a;
|
|
365
433
|
this._Volume = value;
|
|
366
|
-
if (
|
|
367
|
-
this.
|
|
434
|
+
if (value === 'muted') {
|
|
435
|
+
this.close();
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
if (!this._Capture && this._deviceParameters) {
|
|
439
|
+
this.setDevice(this._deviceParameters);
|
|
440
|
+
}
|
|
441
|
+
(_a = this._Capture) === null || _a === void 0 ? void 0 : _a.worker.setVolume(value);
|
|
368
442
|
}
|
|
369
443
|
}
|
|
370
444
|
close() {
|
|
371
445
|
if (this._Capture !== undefined) {
|
|
372
446
|
this._Capture.worker.close();
|
|
447
|
+
stopMediaStream(this._Capture.source.mediaStream);
|
|
373
448
|
this._Capture.source.disconnect(this._Capture.worker.worklet);
|
|
374
449
|
this.controller.audioContexts.release(this._Capture.source.context);
|
|
375
450
|
}
|
|
@@ -386,6 +461,12 @@ export class AudioCapture {
|
|
|
386
461
|
});
|
|
387
462
|
}
|
|
388
463
|
}
|
|
464
|
+
function stopMediaStream(ms) {
|
|
465
|
+
ms.getTracks().forEach(track => {
|
|
466
|
+
track.stop();
|
|
467
|
+
ms.removeTrack(track);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
389
470
|
function openCaptureDevice(controller, parameters, apm) {
|
|
390
471
|
return __awaiter(this, void 0, void 0, function* () {
|
|
391
472
|
const deviceId = parameters.device
|
|
@@ -409,6 +490,7 @@ function openCaptureDevice(controller, parameters, apm) {
|
|
|
409
490
|
]);
|
|
410
491
|
if (result === 'timeout')
|
|
411
492
|
return failure('getUserMedia; timeout');
|
|
493
|
+
hasAudioPermissions = true;
|
|
412
494
|
stream = result;
|
|
413
495
|
}
|
|
414
496
|
catch (reason) {
|
|
@@ -419,4 +501,3 @@ function openCaptureDevice(controller, parameters, apm) {
|
|
|
419
501
|
return success(context.createMediaStreamSource(stream));
|
|
420
502
|
});
|
|
421
503
|
}
|
|
422
|
-
//# sourceMappingURL=audioController.js.map
|
|
@@ -22,7 +22,7 @@ export declare class WebPlugin implements Backend.Plugin {
|
|
|
22
22
|
createAudioCapture(parameters: CreateAudioCaptureParameters): Promise<AudioCapture>;
|
|
23
23
|
enumerateDevices(): Promise<Device[]>;
|
|
24
24
|
setOutputVolume(volume: Volume): void;
|
|
25
|
-
setOutputDevice(device: DeviceParameters): void
|
|
25
|
+
setOutputDevice(device: DeviceParameters): Promise<void>;
|
|
26
26
|
close(): void;
|
|
27
27
|
}
|
|
28
28
|
export declare class Room implements Backend.Room {
|
|
@@ -50,4 +50,3 @@ export declare class Room implements Backend.Room {
|
|
|
50
50
|
private _HandleMediaStart;
|
|
51
51
|
private _HandleMediaStopped;
|
|
52
52
|
}
|
|
53
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -54,7 +54,9 @@ export class WebPlugin {
|
|
|
54
54
|
this._AudioController.playbackSetGlobalVolume(volume);
|
|
55
55
|
}
|
|
56
56
|
setOutputDevice(device) {
|
|
57
|
-
this
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
yield this._AudioController.playbackSetDevice(device.device);
|
|
59
|
+
});
|
|
58
60
|
}
|
|
59
61
|
close() {
|
|
60
62
|
this._AudioController.close();
|
|
@@ -288,4 +290,3 @@ export class Room {
|
|
|
288
290
|
peer.mediaIds.delete(mediaId);
|
|
289
291
|
}
|
|
290
292
|
}
|
|
291
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
export type CaptureSink = (connectionId: number, packet: Uint8Array) => void;
|
|
2
1
|
export interface Activity {
|
|
3
2
|
isSilent: boolean;
|
|
4
3
|
rmsDBFS: number;
|
|
5
4
|
}
|
|
6
|
-
export declare const
|
|
5
|
+
export declare const Silence: Activity;
|
|
7
6
|
export interface VadConfig {
|
|
8
7
|
volumeGate?: {
|
|
9
8
|
attackThreshold: number;
|
|
@@ -14,6 +13,7 @@ export interface VadConfig {
|
|
|
14
13
|
releaseThreshold: number;
|
|
15
14
|
};
|
|
16
15
|
}
|
|
16
|
+
export type CaptureSink = (connectionId: number, packet: Uint8Array) => void;
|
|
17
17
|
export interface CaptureWorker {
|
|
18
18
|
readonly worklet: AudioWorkletNode;
|
|
19
19
|
readonly worker: Worker;
|
|
@@ -28,11 +28,6 @@ export interface CaptureWorker {
|
|
|
28
28
|
setVad(config: VadConfig): void;
|
|
29
29
|
close(): void;
|
|
30
30
|
}
|
|
31
|
-
export declare function createCaptureWorker(context: AudioContext, sink: CaptureSink, refreshRate?: number): Promise<CaptureWorker>;
|
|
32
|
-
export interface PlaybackId {
|
|
33
|
-
connectionId: number;
|
|
34
|
-
mediaId: number;
|
|
35
|
-
}
|
|
36
31
|
export interface PlaybackWorker {
|
|
37
32
|
readonly audioContext: AudioContext;
|
|
38
33
|
receivePacket(connectionId: number, packet: Uint8Array): void;
|
|
@@ -43,4 +38,8 @@ export interface PlaybackWorker {
|
|
|
43
38
|
setVolume(id: PlaybackId, value: number): void;
|
|
44
39
|
close(): void;
|
|
45
40
|
}
|
|
46
|
-
export
|
|
41
|
+
export interface PlaybackId {
|
|
42
|
+
connectionId: number;
|
|
43
|
+
mediaId: number;
|
|
44
|
+
}
|
|
45
|
+
export declare function mergeIds(id: PlaybackId): number;
|
|
@@ -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;
|