@4players/odin-plugin-web 1.0.0-alpha.12 → 1.0.0-alpha.14
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 +2 -1
- package/lib/plugin/audioController.js +25 -8
- package/lib/plugin/mainConnection.js +23 -21
- package/lib/plugin/roomConnection.d.ts +4 -3
- package/lib/plugin/roomConnection.js +15 -22
- package/lib/plugin/rpcConnection.d.ts +7 -13
- package/lib/plugin/token.d.ts +2 -3
- package/lib/worker/index.js +1 -1
- package/package.json +4 -7
|
@@ -87,7 +87,8 @@ export declare class AudioCapture implements Backend.AudioCapture {
|
|
|
87
87
|
private _Vad;
|
|
88
88
|
private _Apm;
|
|
89
89
|
private _Volume;
|
|
90
|
-
private
|
|
90
|
+
private _DeviceParameters?;
|
|
91
|
+
private _DeviceCb;
|
|
91
92
|
get vad(): Backend.VadConfig;
|
|
92
93
|
get apm(): Backend.ApmConfig;
|
|
93
94
|
get volume(): Backend.Volume;
|
|
@@ -339,7 +339,7 @@ export class AudioCapture {
|
|
|
339
339
|
}
|
|
340
340
|
get deviceId() {
|
|
341
341
|
var _a, _b;
|
|
342
|
-
return (_b = (_a = this.
|
|
342
|
+
return (_b = (_a = this._DeviceParameters) === null || _a === void 0 ? void 0 : _a.device) === null || _b === void 0 ? void 0 : _b.device.deviceId;
|
|
343
343
|
}
|
|
344
344
|
constructor(controller, parameters) {
|
|
345
345
|
this.controller = controller;
|
|
@@ -347,6 +347,19 @@ export class AudioCapture {
|
|
|
347
347
|
this._Vad = defaultVad;
|
|
348
348
|
this._Apm = defaultApm;
|
|
349
349
|
this._Volume = 1;
|
|
350
|
+
this._DeviceCb = () => __awaiter(this, void 0, void 0, function* () {
|
|
351
|
+
var _a, _b;
|
|
352
|
+
const devices = yield this.controller.enumerateDevices();
|
|
353
|
+
const isListed = devices.some((device) => {
|
|
354
|
+
var _a, _b;
|
|
355
|
+
return (device.device.deviceId ===
|
|
356
|
+
((_b = (_a = this._DeviceParameters) === null || _a === void 0 ? void 0 : _a.device) === null || _b === void 0 ? void 0 : _b.device.deviceId));
|
|
357
|
+
});
|
|
358
|
+
if (!isListed) {
|
|
359
|
+
(_b = (_a = this._DeviceParameters) === null || _a === void 0 ? void 0 : _a.onStatusChanged) === null || _b === void 0 ? void 0 : _b.call(_a, 'stopped');
|
|
360
|
+
navigator.mediaDevices.removeEventListener('devicechange', this._DeviceCb);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
350
363
|
if (parameters.apm) {
|
|
351
364
|
this.setApm(parameters.apm);
|
|
352
365
|
}
|
|
@@ -397,25 +410,28 @@ export class AudioCapture {
|
|
|
397
410
|
setApm(config) {
|
|
398
411
|
return __awaiter(this, void 0, void 0, function* () {
|
|
399
412
|
this._Apm = config;
|
|
400
|
-
if (this.
|
|
401
|
-
yield this.setDevice(this.
|
|
413
|
+
if (this._DeviceParameters) {
|
|
414
|
+
yield this.setDevice(this._DeviceParameters);
|
|
402
415
|
}
|
|
403
416
|
});
|
|
404
417
|
}
|
|
405
418
|
setDevice(parameters) {
|
|
406
419
|
var _a;
|
|
407
420
|
return __awaiter(this, void 0, void 0, function* () {
|
|
408
|
-
const rollbackParams = this.
|
|
409
|
-
this.
|
|
421
|
+
const rollbackParams = this._DeviceParameters;
|
|
422
|
+
this._DeviceParameters = parameters;
|
|
410
423
|
if (this._Volume === 'muted') {
|
|
411
424
|
return;
|
|
412
425
|
}
|
|
413
426
|
const device = yield openCaptureDevice(this.controller, parameters, this._Apm);
|
|
414
427
|
if (device.type !== 'Success') {
|
|
415
428
|
console.error(`unable to open capture device; ${device.reason}`);
|
|
416
|
-
this.
|
|
429
|
+
this._DeviceParameters = rollbackParams;
|
|
417
430
|
return;
|
|
418
431
|
}
|
|
432
|
+
if (this._DeviceParameters.onStatusChanged) {
|
|
433
|
+
navigator.mediaDevices.addEventListener('devicechange', this._DeviceCb);
|
|
434
|
+
}
|
|
419
435
|
if (this._Capture !== undefined) {
|
|
420
436
|
stopMediaStream(this._Capture.source.mediaStream);
|
|
421
437
|
this._Capture.source.disconnect(this._Capture.worker.worklet);
|
|
@@ -445,8 +461,8 @@ export class AudioCapture {
|
|
|
445
461
|
this.close();
|
|
446
462
|
}
|
|
447
463
|
else {
|
|
448
|
-
if (!this._Capture && this.
|
|
449
|
-
this.setDevice(this.
|
|
464
|
+
if (!this._Capture && this._DeviceParameters) {
|
|
465
|
+
this.setDevice(this._DeviceParameters);
|
|
450
466
|
}
|
|
451
467
|
(_a = this._Capture) === null || _a === void 0 ? void 0 : _a.worker.setVolume(value);
|
|
452
468
|
}
|
|
@@ -458,6 +474,7 @@ export class AudioCapture {
|
|
|
458
474
|
this._Capture.source.disconnect(this._Capture.worker.worklet);
|
|
459
475
|
this.controller.audioContexts.release(this._Capture.source.context);
|
|
460
476
|
}
|
|
477
|
+
navigator.mediaDevices.removeEventListener('devicechange', this._DeviceCb);
|
|
461
478
|
this._Capture = undefined;
|
|
462
479
|
}
|
|
463
480
|
_UpdateMedias() {
|
|
@@ -46,29 +46,31 @@ export class MainConnection {
|
|
|
46
46
|
return this.connection.closed;
|
|
47
47
|
}
|
|
48
48
|
webRtcReady() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
const result = isReady();
|
|
61
|
-
if (result !== undefined)
|
|
62
|
-
return Promise.resolve(result);
|
|
63
|
-
return new Promise((accept) => {
|
|
64
|
-
const onConnectionStateChanged = () => {
|
|
65
|
-
const result = isReady();
|
|
66
|
-
if (result !== undefined) {
|
|
67
|
-
this.webRtc.removeEventListener('connectionstatechange', onConnectionStateChanged);
|
|
68
|
-
accept(result);
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
const isReady = () => {
|
|
51
|
+
switch (this.webRtc.connectionState) {
|
|
52
|
+
case 'connected':
|
|
53
|
+
return true;
|
|
54
|
+
case 'failed':
|
|
55
|
+
case 'closed':
|
|
56
|
+
return false;
|
|
57
|
+
default:
|
|
58
|
+
return undefined;
|
|
69
59
|
}
|
|
70
60
|
};
|
|
71
|
-
|
|
61
|
+
const result = isReady();
|
|
62
|
+
if (result !== undefined)
|
|
63
|
+
return result;
|
|
64
|
+
return new Promise((accept) => {
|
|
65
|
+
const onConnectionStateChanged = () => {
|
|
66
|
+
const result = isReady();
|
|
67
|
+
if (result !== undefined) {
|
|
68
|
+
this.webRtc.removeEventListener('connectionstatechange', onConnectionStateChanged);
|
|
69
|
+
accept(result);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
this.webRtc.addEventListener('connectionstatechange', onConnectionStateChanged);
|
|
73
|
+
});
|
|
72
74
|
});
|
|
73
75
|
}
|
|
74
76
|
constructor(id, url, onDatagram, connection, webRtc) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Backend, RoomCommands, Result } from '@4players/odin-common';
|
|
2
|
-
import { z } from 'zod';
|
|
1
|
+
import { Backend, RoomCommands, Result, Infer } from '@4players/odin-common';
|
|
3
2
|
import { ConnectionPool } from './connectionPool';
|
|
4
3
|
import { MainConnection } from './mainConnection';
|
|
5
4
|
import { Token } from './token';
|
|
@@ -14,6 +13,8 @@ export declare class RoomConnection {
|
|
|
14
13
|
private _Token;
|
|
15
14
|
private _UserData;
|
|
16
15
|
private _Position;
|
|
16
|
+
private _ConnectionFailures;
|
|
17
|
+
private _FailureLimit;
|
|
17
18
|
private _LastTokenRenew;
|
|
18
19
|
private readonly _Closed;
|
|
19
20
|
get token(): Token;
|
|
@@ -23,7 +24,7 @@ export declare class RoomConnection {
|
|
|
23
24
|
get mainConnection(): MainConnection | undefined;
|
|
24
25
|
constructor(connectionPool: ConnectionPool, onEvent: Backend.OnEvent, gateway: URL | undefined, token: Token, roomId: string, userData: Uint8Array, position: [number, number, number]);
|
|
25
26
|
request(name: string, properties: unknown): Promise<Result<unknown> | 'closed'>;
|
|
26
|
-
typedRequest<Name extends Extract<keyof RoomCommands, string>>(name: Name, properties:
|
|
27
|
+
typedRequest<Name extends Extract<keyof RoomCommands, string>>(name: Name, properties: Infer<RoomCommands[Name]['request']>): Promise<Result<Infer<RoomCommands[Name]['response']>> | 'closed'>;
|
|
27
28
|
close(): void;
|
|
28
29
|
get renewTokenIn(): number;
|
|
29
30
|
private _Main;
|
|
@@ -8,7 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { Selector, failure, sleep, success, RoomCommandsRpc, } from '@4players/odin-common';
|
|
11
|
-
import { z } from 'zod';
|
|
12
11
|
import { RpcConnection } from './rpcConnection';
|
|
13
12
|
import { Token } from './token';
|
|
14
13
|
import { ConnectTimeout, MinTokenLifetime, MinTokenRefreshInterval, } from './config';
|
|
@@ -34,6 +33,8 @@ export class RoomConnection {
|
|
|
34
33
|
this.gateway = gateway;
|
|
35
34
|
this.roomId = roomId;
|
|
36
35
|
this._Close = new AbortController();
|
|
36
|
+
this._ConnectionFailures = 0;
|
|
37
|
+
this._FailureLimit = 5;
|
|
37
38
|
this._LastTokenRenew = performance.now();
|
|
38
39
|
this._Closed = new Promise((accept) => this._Close.signal.addEventListener('abort', () => accept('closed'), {
|
|
39
40
|
once: true,
|
|
@@ -144,6 +145,10 @@ export class RoomConnection {
|
|
|
144
145
|
if (mainConnection === 'closed')
|
|
145
146
|
return failure('connection pool closed'); // connection pool is closed
|
|
146
147
|
if (mainConnection.type === 'Failure') {
|
|
148
|
+
if (this._ConnectionFailures < this._FailureLimit) {
|
|
149
|
+
this._ConnectionFailures++;
|
|
150
|
+
return failure(`Connection failed; ${mainConnection.reason}`);
|
|
151
|
+
}
|
|
147
152
|
this._ChangeStatus('Joining', `connection failed; ${mainConnection.reason}`);
|
|
148
153
|
return success('continue');
|
|
149
154
|
}
|
|
@@ -180,13 +185,11 @@ export class RoomConnection {
|
|
|
180
185
|
});
|
|
181
186
|
}
|
|
182
187
|
_ChangeStatus(status, message) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
this.onEvent('RoomStatusChanged', properties);
|
|
189
|
-
});
|
|
188
|
+
const properties = {
|
|
189
|
+
status,
|
|
190
|
+
message,
|
|
191
|
+
};
|
|
192
|
+
this.onEvent('RoomStatusChanged', properties);
|
|
190
193
|
}
|
|
191
194
|
_HandleConnection(main, webSocket) {
|
|
192
195
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -264,6 +267,7 @@ export class RoomConnection {
|
|
|
264
267
|
}
|
|
265
268
|
}
|
|
266
269
|
function contactGateway(gateway, token, signal) {
|
|
270
|
+
var _a, _b;
|
|
267
271
|
return __awaiter(this, void 0, void 0, function* () {
|
|
268
272
|
try {
|
|
269
273
|
const response = yield fetch(gateway, {
|
|
@@ -275,24 +279,13 @@ function contactGateway(gateway, token, signal) {
|
|
|
275
279
|
},
|
|
276
280
|
signal,
|
|
277
281
|
});
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
result: z.object({
|
|
281
|
-
token: z.string(),
|
|
282
|
-
}),
|
|
283
|
-
}),
|
|
284
|
-
z.object({
|
|
285
|
-
error: z.object({
|
|
286
|
-
message: z.string(),
|
|
287
|
-
}),
|
|
288
|
-
}),
|
|
289
|
-
]);
|
|
290
|
-
const body = schema.parse(yield response.json());
|
|
282
|
+
// TODO: re-add validation once schemas are available in common
|
|
283
|
+
const body = yield response.json();
|
|
291
284
|
if ('result' in body) {
|
|
292
285
|
return Token.parse(body.result.token);
|
|
293
286
|
}
|
|
294
287
|
else {
|
|
295
|
-
console.error(`gateway rejected token; ${body.error.message}`);
|
|
288
|
+
console.error(`gateway rejected token; ${(_b = (_a = body.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : 'malformed response'}`);
|
|
296
289
|
return success('rejected');
|
|
297
290
|
}
|
|
298
291
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Result, Accept, MessagePackRpc, Notifications } from '@4players/odin-common';
|
|
1
|
+
import { Result, Accept, MessagePackRpc, Notifications, Infer, Commands } from '@4players/odin-common';
|
|
3
2
|
export interface RpcMessage {
|
|
4
3
|
name: string;
|
|
5
4
|
properties: unknown;
|
|
@@ -31,25 +30,20 @@ export declare class RpcConnection {
|
|
|
31
30
|
private _OnEvent;
|
|
32
31
|
private _Cleanup;
|
|
33
32
|
}
|
|
34
|
-
export type Commands = Record<string, {
|
|
35
|
-
request: z.ZodTypeAny;
|
|
36
|
-
response: z.ZodTypeAny;
|
|
37
|
-
}>;
|
|
38
|
-
export type Events = Record<string, z.ZodTypeAny>;
|
|
39
33
|
export interface TypedRpcMessage<Name extends string, Properties> extends RpcMessage {
|
|
40
34
|
name: Name;
|
|
41
35
|
properties: Properties;
|
|
42
36
|
}
|
|
43
|
-
export type RealizedEvents<E extends
|
|
44
|
-
[Name in Extract<keyof E, string>]: TypedRpcMessage<Name,
|
|
37
|
+
export type RealizedEvents<E extends Notifications> = {
|
|
38
|
+
[Name in Extract<keyof E, string>]: TypedRpcMessage<Name, Infer<E[Name]>>;
|
|
45
39
|
}[Extract<keyof E, string>];
|
|
46
|
-
export declare class TypedRpcConnection<C extends Commands, E extends
|
|
40
|
+
export declare class TypedRpcConnection<C extends Commands, E extends Notifications> extends RpcConnection {
|
|
47
41
|
readonly _Commands: C;
|
|
48
42
|
readonly _Events: E;
|
|
49
43
|
constructor(webSocket: WebSocket, _Commands: C, _Events: E);
|
|
50
|
-
request<Name extends Extract<keyof C, string>>(name: Name, properties:
|
|
51
|
-
request<Name extends Extract<keyof C, string>>(name: Name, properties:
|
|
52
|
-
notify<Name extends Extract<keyof C, string>>(name: Name, properties:
|
|
44
|
+
request<Name extends Extract<keyof C, string>>(name: Name, properties: Infer<C[Name]['request']>): Promise<Result<Infer<C[Name]['response']>> | 'closed'>;
|
|
45
|
+
request<Name extends Extract<keyof C, string>>(name: Name, properties: Infer<C[Name]['request']>, timeout: number): Promise<Result<Infer<C[Name]['response']>> | 'closed' | 'timeout'>;
|
|
46
|
+
notify<Name extends Extract<keyof C, string>>(name: Name, properties: Infer<C[Name]['request']>): void;
|
|
53
47
|
recv(): Promise<RealizedEvents<E> | 'closed'>;
|
|
54
48
|
}
|
|
55
49
|
export declare function parseRpc(buffer: ArrayBuffer): Result<MessagePackRpc>;
|
package/lib/plugin/token.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TokenAudienceSchema, TokenClaims, Result } from '@4players/odin-common';
|
|
1
|
+
import { TokenAudienceSchema, TokenClaims, Result, Infer } from '@4players/odin-common';
|
|
3
2
|
export declare class Token {
|
|
4
3
|
readonly text: string;
|
|
5
4
|
readonly claims: TokenClaims;
|
|
@@ -11,6 +10,6 @@ export declare class Token {
|
|
|
11
10
|
get address(): URL | undefined;
|
|
12
11
|
get upstream(): Token | undefined;
|
|
13
12
|
get defaultRoomId(): string | undefined;
|
|
14
|
-
hasAudience(audience:
|
|
13
|
+
hasAudience(audience: Infer<typeof TokenAudienceSchema>): boolean;
|
|
15
14
|
toString(): string;
|
|
16
15
|
}
|