@4players/odin-plugin-web 1.0.0-alpha.2 → 1.0.0-alpha.20
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/common/msgpack.d.ts +2 -0
- package/lib/common/msgpack.js +117 -0
- package/{backend/lib → lib/plugin}/config.d.ts +5 -4
- package/lib/plugin/config.js +22 -0
- package/{backend/lib → lib/plugin}/connectionPool.d.ts +3 -3
- package/{backend/lib → lib/plugin}/connectionPool.js +32 -13
- package/lib/plugin/deviceManager.d.ts +12 -0
- package/lib/plugin/deviceManager.js +120 -0
- package/lib/plugin/h3/mainConnection.d.ts +31 -0
- package/lib/plugin/h3/mainConnection.js +195 -0
- package/{backend/lib → lib/plugin}/index.d.ts +30 -13
- package/lib/plugin/index.js +404 -0
- package/lib/plugin/mainConnection.d.ts +30 -0
- package/lib/plugin/mainConnection.js +21 -0
- package/{backend/lib/audioController.d.ts → lib/plugin/mediaController.d.ts} +12 -48
- package/lib/plugin/mediaController.js +215 -0
- package/lib/plugin/medias/audio-capture.d.ts +30 -0
- package/lib/plugin/medias/audio-capture.js +224 -0
- package/lib/plugin/medias/audio-playback.d.ts +13 -0
- package/lib/plugin/medias/audio-playback.js +40 -0
- package/lib/plugin/medias/video-capture.d.ts +15 -0
- package/lib/plugin/medias/video-capture.js +69 -0
- package/lib/plugin/medias/video-playback.d.ts +13 -0
- package/lib/plugin/medias/video-playback.js +20 -0
- package/{backend/lib → lib/plugin}/roomConnection.d.ts +9 -6
- package/{backend/lib → lib/plugin}/roomConnection.js +74 -53
- package/lib/plugin/rpcConnection.d.ts +57 -0
- package/{backend/lib → lib/plugin}/rpcConnection.js +129 -83
- package/lib/plugin/token.d.ts +13 -0
- package/{backend/lib → lib/plugin}/token.js +8 -9
- package/lib/plugin/webrtc/mainConnection.d.ts +53 -0
- package/lib/plugin/webrtc/mainConnection.js +455 -0
- package/lib/plugin/webrtc/websocket.d.ts +3 -0
- package/lib/plugin/webrtc/websocket.js +56 -0
- 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 +27 -0
- package/lib/worker/shared/capture.js +63 -0
- package/lib/worker/shared/index.d.ts +3 -0
- package/lib/worker/shared/index.js +147 -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 +20 -0
- package/lib/worker/shared/playback.js +78 -0
- package/lib/worker/unshared/capture.d.ts +27 -0
- package/lib/worker/unshared/capture.js +66 -0
- package/lib/worker/unshared/index.d.ts +3 -0
- package/lib/worker/unshared/index.js +170 -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 +22 -0
- package/lib/worker/unshared/playback.js +83 -0
- package/package.json +29 -26
- package/backend/lib/audioController.d.ts.map +0 -1
- package/backend/lib/audioController.js +0 -442
- package/backend/lib/audioController.js.map +0 -1
- package/backend/lib/config.d.ts.map +0 -1
- package/backend/lib/config.js +0 -11
- 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 +0 -293
- package/backend/lib/index.js.map +0 -1
- package/backend/lib/mainConnection.d.ts +0 -40
- package/backend/lib/mainConnection.d.ts.map +0 -1
- package/backend/lib/mainConnection.js +0 -294
- 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 +0 -49
- package/backend/lib/rpcConnection.d.ts.map +0 -1
- package/backend/lib/rpcConnection.js.map +0 -1
- package/backend/lib/token.d.ts +0 -16
- 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
|
@@ -1,27 +1,43 @@
|
|
|
1
|
-
import { ConnectionPool } from './connectionPool';
|
|
2
1
|
import { Backend } from '@4players/odin-common';
|
|
3
|
-
import {
|
|
2
|
+
import { AudioContextFactory, CreateAudioCaptureParameters, CreateAudioPlaybackParameters, Device } from './mediaController';
|
|
3
|
+
import { ConnectionPool } from './connectionPool';
|
|
4
4
|
import { MainConnection } from './mainConnection';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { AudioCapture } from './medias/audio-capture';
|
|
6
|
+
import { VideoCapture } from './medias/video-capture';
|
|
7
|
+
import { VideoPlayback } from './medias/video-playback';
|
|
8
|
+
import { AudioPlayback } from './medias/audio-playback';
|
|
9
|
+
import JoinRoomParameters = Backend.JoinRoomParameters;
|
|
10
|
+
export type { LogFilters } from '@4players/odin-common';
|
|
11
|
+
export { logger } from './config';
|
|
12
|
+
type Plugin = Backend.Plugin;
|
|
7
13
|
export interface DeviceParameters {
|
|
8
14
|
readonly device?: Device;
|
|
9
15
|
onStatusChanged?: Backend.OnStatusChanged;
|
|
10
16
|
}
|
|
11
|
-
export declare
|
|
12
|
-
|
|
17
|
+
export declare enum Transport {
|
|
18
|
+
H3 = "h3",
|
|
19
|
+
WebRTC = "webrtc"
|
|
20
|
+
}
|
|
21
|
+
export interface WebPluginOptions {
|
|
22
|
+
transport: Transport;
|
|
23
|
+
}
|
|
24
|
+
export declare class WebPlugin implements Plugin {
|
|
25
|
+
readonly options: WebPluginOptions;
|
|
26
|
+
readonly version = "2";
|
|
13
27
|
private _NextRoomId;
|
|
14
28
|
private _PlaybackVolume;
|
|
15
29
|
private readonly _ConnectionPool;
|
|
16
|
-
private readonly
|
|
30
|
+
private readonly _MediaController;
|
|
17
31
|
get playbackVolume(): Backend.Volume;
|
|
18
|
-
static create(audioContextFactory: AudioContextFactory): Promise<WebPlugin>;
|
|
32
|
+
static create(audioContextFactory: AudioContextFactory, options?: WebPluginOptions): Promise<WebPlugin>;
|
|
19
33
|
private constructor();
|
|
20
34
|
joinRoom(parameters: JoinRoomParameters): Room;
|
|
21
35
|
createAudioPlayback(parameters: CreateAudioPlaybackParameters): Promise<AudioPlayback>;
|
|
22
36
|
createAudioCapture(parameters: CreateAudioCaptureParameters): Promise<AudioCapture>;
|
|
37
|
+
createVideoCapture(ms: MediaStream, customType?: string): Promise<VideoCapture>;
|
|
38
|
+
createVideoPlayback(parameters: Backend.CreateVideoPlaybackParameters): Promise<VideoPlayback>;
|
|
23
39
|
enumerateDevices(): Promise<Device[]>;
|
|
24
|
-
setOutputVolume(volume: Volume): void;
|
|
40
|
+
setOutputVolume(volume: Backend.Volume): void;
|
|
25
41
|
setOutputDevice(device: DeviceParameters): Promise<void>;
|
|
26
42
|
close(): void;
|
|
27
43
|
}
|
|
@@ -34,10 +50,12 @@ export declare class Room implements Backend.Room {
|
|
|
34
50
|
private readonly _Peers;
|
|
35
51
|
private readonly _AvailableMediaIds;
|
|
36
52
|
get mainConnection(): MainConnection | undefined;
|
|
37
|
-
constructor(id: number, connectionPool: ConnectionPool, parameters: JoinRoomParameters);
|
|
53
|
+
constructor(id: number, connectionPool: ConnectionPool, parameters: JoinRoomParameters, options: WebPluginOptions);
|
|
54
|
+
get token(): string;
|
|
55
|
+
get cipher(): Backend.Cipher | undefined;
|
|
38
56
|
request(method: string, properties: unknown): Promise<unknown>;
|
|
39
|
-
link(media: Media): void
|
|
40
|
-
unlink(media: Media): void;
|
|
57
|
+
link(media: Backend.Media): Promise<void>;
|
|
58
|
+
unlink(media: Backend.Media): void;
|
|
41
59
|
close(): void;
|
|
42
60
|
private _HandleEvent;
|
|
43
61
|
private _HandleKnownEvent;
|
|
@@ -50,4 +68,3 @@ export declare class Room implements Backend.Room {
|
|
|
50
68
|
private _HandleMediaStart;
|
|
51
69
|
private _HandleMediaStopped;
|
|
52
70
|
}
|
|
53
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,404 @@
|
|
|
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 { assert, generateUUID, OdinError, RoomNotificationsRpc, unwrap, } from '@4players/odin-common';
|
|
11
|
+
import { AudioContextCollection, MediaController, } from './mediaController';
|
|
12
|
+
import { ConnectionPool } from './connectionPool';
|
|
13
|
+
import { RoomConnection } from './roomConnection';
|
|
14
|
+
import { parseRpcMessage } from './rpcConnection';
|
|
15
|
+
import { Token } from './token';
|
|
16
|
+
import { AudioCapture } from './medias/audio-capture';
|
|
17
|
+
import { enumerateDevices } from './deviceManager';
|
|
18
|
+
import { VideoCapture } from './medias/video-capture';
|
|
19
|
+
import { VideoPlayback } from './medias/video-playback';
|
|
20
|
+
import { AudioPlayback } from './medias/audio-playback';
|
|
21
|
+
import { logger } from './config';
|
|
22
|
+
export { logger } from './config';
|
|
23
|
+
export var Transport;
|
|
24
|
+
(function (Transport) {
|
|
25
|
+
Transport["H3"] = "h3";
|
|
26
|
+
Transport["WebRTC"] = "webrtc";
|
|
27
|
+
})(Transport || (Transport = {}));
|
|
28
|
+
export class WebPlugin {
|
|
29
|
+
get playbackVolume() {
|
|
30
|
+
return this._PlaybackVolume;
|
|
31
|
+
}
|
|
32
|
+
static create(audioContextFactory, options) {
|
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
logger.info(['Other'], 'Using ODIN Plugin Web!');
|
|
35
|
+
// eslint-disable-next-line prefer-const
|
|
36
|
+
let audioController;
|
|
37
|
+
const pool = new ConnectionPool((connectionId, packet) => audioController.receivePacket(connectionId, packet));
|
|
38
|
+
const audioContexts = new AudioContextCollection(audioContextFactory);
|
|
39
|
+
audioController = new MediaController(audioContexts, pool.sendDatagram.bind(pool));
|
|
40
|
+
return new WebPlugin(pool, audioController, options);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
constructor(connectionPool, audioController, options = { transport: Transport.H3 }) {
|
|
44
|
+
this.options = options;
|
|
45
|
+
this.version = '2';
|
|
46
|
+
this._NextRoomId = 0;
|
|
47
|
+
this._PlaybackVolume = 1;
|
|
48
|
+
this._ConnectionPool = connectionPool;
|
|
49
|
+
this._MediaController = audioController;
|
|
50
|
+
}
|
|
51
|
+
joinRoom(parameters) {
|
|
52
|
+
return new Room(this._NextRoomId++, this._ConnectionPool, parameters, this.options);
|
|
53
|
+
}
|
|
54
|
+
createAudioPlayback(parameters) {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
return this._MediaController.createAudioPlayback(parameters);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
createAudioCapture(parameters) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
return this._MediaController.createAudioCapture(parameters);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
createVideoCapture(ms, customType) {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
return this._MediaController.createVideoCapture(ms, customType);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
createVideoPlayback(parameters) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
return new VideoPlayback(parameters.uid, parameters.customType);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
enumerateDevices() {
|
|
75
|
+
return enumerateDevices();
|
|
76
|
+
}
|
|
77
|
+
setOutputVolume(volume) {
|
|
78
|
+
this._MediaController.playbackSetGlobalVolume(volume);
|
|
79
|
+
}
|
|
80
|
+
setOutputDevice(device) {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
yield this._MediaController.playbackSetDevice(device.device);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
close() {
|
|
86
|
+
logger.debug(['Other', 'Plugin.close()']);
|
|
87
|
+
this._MediaController.close();
|
|
88
|
+
this._ConnectionPool.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export class Room {
|
|
92
|
+
get mainConnection() {
|
|
93
|
+
return this._Connection.mainConnection;
|
|
94
|
+
}
|
|
95
|
+
constructor(id, connectionPool, parameters, options) {
|
|
96
|
+
var _a, _b, _c;
|
|
97
|
+
this._Captures = new Map();
|
|
98
|
+
this._Playbacks = new Map();
|
|
99
|
+
this._Peers = new Map();
|
|
100
|
+
this._AvailableMediaIds = [];
|
|
101
|
+
const { gateway, onEvent } = parameters;
|
|
102
|
+
const token = unwrap(Token.parse(parameters.token));
|
|
103
|
+
const roomId = (_a = parameters.roomId) !== null && _a !== void 0 ? _a : token.defaultRoomId;
|
|
104
|
+
const userData = (_b = parameters.userData) !== null && _b !== void 0 ? _b : new Uint8Array(0);
|
|
105
|
+
const position = (_c = parameters.position) !== null && _c !== void 0 ? _c : [0, 0, 0];
|
|
106
|
+
assert(roomId !== undefined, 'room id required for multi-room-tokens');
|
|
107
|
+
this._Id = id;
|
|
108
|
+
this._OnEvent = onEvent;
|
|
109
|
+
this._Connection = new RoomConnection(connectionPool, options.transport, this._HandleEvent.bind(this), gateway ? new URL(gateway) : undefined, token, roomId, userData, position);
|
|
110
|
+
}
|
|
111
|
+
get token() {
|
|
112
|
+
return this._Connection.token.text;
|
|
113
|
+
}
|
|
114
|
+
get cipher() {
|
|
115
|
+
return undefined; // not implemented
|
|
116
|
+
}
|
|
117
|
+
request(method, properties) {
|
|
118
|
+
return this._Connection.request(method, properties);
|
|
119
|
+
}
|
|
120
|
+
link(media) {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
var _a, _b, _c, _d;
|
|
123
|
+
logger.debug(['Audio'], 'Room.link() media', media);
|
|
124
|
+
if (media instanceof AudioPlayback) {
|
|
125
|
+
const entry = (_a = this._Playbacks.get(media.uid)) !== null && _a !== void 0 ? _a : {
|
|
126
|
+
media: undefined,
|
|
127
|
+
playback: undefined,
|
|
128
|
+
};
|
|
129
|
+
if (entry.playback !== undefined) {
|
|
130
|
+
this.unlink(entry.playback);
|
|
131
|
+
}
|
|
132
|
+
if (entry.media !== undefined) {
|
|
133
|
+
media.start(entry.media);
|
|
134
|
+
}
|
|
135
|
+
entry.playback = media;
|
|
136
|
+
this._Playbacks.set(media.uid, entry);
|
|
137
|
+
}
|
|
138
|
+
else if (media instanceof AudioCapture) {
|
|
139
|
+
let entry = this._Captures.get(media);
|
|
140
|
+
if (entry) {
|
|
141
|
+
this.unlink(media);
|
|
142
|
+
}
|
|
143
|
+
const mediaId = this.mainConnection !== undefined && this._AvailableMediaIds.shift();
|
|
144
|
+
entry = {
|
|
145
|
+
media: mediaId
|
|
146
|
+
? {
|
|
147
|
+
connectionId: this.mainConnection.id,
|
|
148
|
+
mediaId,
|
|
149
|
+
}
|
|
150
|
+
: undefined,
|
|
151
|
+
uid: generateUUID(),
|
|
152
|
+
};
|
|
153
|
+
this._Captures.set(media, entry);
|
|
154
|
+
if (entry.media !== undefined) {
|
|
155
|
+
media.start(this._Connection, entry.media, entry.uid);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (media instanceof VideoCapture) {
|
|
159
|
+
let mediaEntry = this._Captures.get(media);
|
|
160
|
+
if (mediaEntry) {
|
|
161
|
+
this.unlink(media);
|
|
162
|
+
}
|
|
163
|
+
if (media.mediaStream) {
|
|
164
|
+
const mediaId = this.mainConnection !== undefined && this._AvailableMediaIds.shift();
|
|
165
|
+
mediaEntry = {
|
|
166
|
+
media: mediaId
|
|
167
|
+
? {
|
|
168
|
+
connectionId: this.mainConnection.id,
|
|
169
|
+
mediaId,
|
|
170
|
+
}
|
|
171
|
+
: undefined,
|
|
172
|
+
uid: generateUUID(),
|
|
173
|
+
};
|
|
174
|
+
this._Captures.set(media, mediaEntry);
|
|
175
|
+
if (mediaEntry.media !== undefined) {
|
|
176
|
+
// @TODO Check if we also need to send the StartMedia rpc
|
|
177
|
+
(_b = this.mainConnection) === null || _b === void 0 ? void 0 : _b.startLocalVideo(mediaEntry.media.mediaId, media.mediaStream.getTracks()[0]);
|
|
178
|
+
media.start(this._Connection, mediaEntry.media, mediaEntry.uid);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else if (media instanceof VideoPlayback) {
|
|
183
|
+
const entry = (_c = this._Playbacks.get(media.uid)) !== null && _c !== void 0 ? _c : {
|
|
184
|
+
media: undefined,
|
|
185
|
+
playback: undefined,
|
|
186
|
+
};
|
|
187
|
+
if (entry.playback !== undefined) {
|
|
188
|
+
this.unlink(entry.playback);
|
|
189
|
+
}
|
|
190
|
+
if (entry.media !== undefined) {
|
|
191
|
+
const track = yield ((_d = this.mainConnection) === null || _d === void 0 ? void 0 : _d.startRemoteVideo(entry.media.mediaId));
|
|
192
|
+
if (track) {
|
|
193
|
+
media.setMediaStream(new MediaStream([track]));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
entry.playback = media;
|
|
197
|
+
this._Playbacks.set(media.uid, entry);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
throw new OdinError('invalid media');
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
unlink(media) {
|
|
205
|
+
var _a, _b;
|
|
206
|
+
logger.debug(['Audio'], 'Room.unlink() media', media);
|
|
207
|
+
if (media instanceof AudioPlayback || media instanceof VideoPlayback) {
|
|
208
|
+
const entry = this._Playbacks.get(media.uid);
|
|
209
|
+
if ((entry === null || entry === void 0 ? void 0 : entry.playback) !== media)
|
|
210
|
+
return;
|
|
211
|
+
entry.playback = undefined;
|
|
212
|
+
if (entry.media !== undefined) {
|
|
213
|
+
if (media instanceof AudioPlayback) {
|
|
214
|
+
media.stop(entry.media);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
(_a = this.mainConnection) === null || _a === void 0 ? void 0 : _a.stopRemoteVideo(entry.media.mediaId);
|
|
218
|
+
// @TODO check if the MediaStream and its tracks have to get closed manually.
|
|
219
|
+
media.setMediaStream(undefined);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
this._Playbacks.set(media.uid, entry);
|
|
223
|
+
}
|
|
224
|
+
else if (media instanceof AudioCapture || media instanceof VideoCapture) {
|
|
225
|
+
const entry = this._Captures.get(media);
|
|
226
|
+
if (entry === undefined)
|
|
227
|
+
return;
|
|
228
|
+
if (entry.media !== undefined) {
|
|
229
|
+
media.stop(this._Connection, entry.media);
|
|
230
|
+
this._AvailableMediaIds.push(entry.media.mediaId);
|
|
231
|
+
if (media instanceof VideoCapture) {
|
|
232
|
+
(_b = this.mainConnection) === null || _b === void 0 ? void 0 : _b.stopLocalVideo(entry.media.mediaId);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
this._Captures.delete(media);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
throw new Error('invalid media');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
close() {
|
|
242
|
+
logger.debug(['Other', 'Room.close()']);
|
|
243
|
+
this._Connection.close();
|
|
244
|
+
}
|
|
245
|
+
_HandleEvent(method, properties) {
|
|
246
|
+
const rpc = parseRpcMessage(RoomNotificationsRpc, {
|
|
247
|
+
name: method,
|
|
248
|
+
properties,
|
|
249
|
+
});
|
|
250
|
+
if (rpc !== undefined) {
|
|
251
|
+
this._HandleKnownEvent(rpc);
|
|
252
|
+
properties = rpc.properties;
|
|
253
|
+
}
|
|
254
|
+
this._OnEvent(method, properties);
|
|
255
|
+
}
|
|
256
|
+
_HandleKnownEvent(event) {
|
|
257
|
+
switch (event.name) {
|
|
258
|
+
case 'RoomStatusChanged':
|
|
259
|
+
if (event.properties.status !== 'Joined') {
|
|
260
|
+
this._HandleConnectionLost();
|
|
261
|
+
}
|
|
262
|
+
break;
|
|
263
|
+
case 'RoomUpdated':
|
|
264
|
+
for (const update of event.properties.updates) {
|
|
265
|
+
this._HandleRoomUpdate(update);
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
case 'PeerUpdated':
|
|
269
|
+
this._HandlePeerUpdate(event.properties);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
_HandleConnectionLost() {
|
|
274
|
+
for (const peerId of this._Peers.keys()) {
|
|
275
|
+
this._HandlePeerLeft(peerId);
|
|
276
|
+
}
|
|
277
|
+
for (const [capture, entry] of this._Captures) {
|
|
278
|
+
if (entry.media === undefined)
|
|
279
|
+
continue;
|
|
280
|
+
if (capture instanceof VideoCapture) {
|
|
281
|
+
// @TODO Check if it needs implementation
|
|
282
|
+
logger.debug(['Connection', 'Video'], '_HandleConnectionLost() VideoCapture');
|
|
283
|
+
}
|
|
284
|
+
if (capture instanceof AudioCapture) {
|
|
285
|
+
capture.stop(this._Connection, entry.media);
|
|
286
|
+
entry.media = undefined;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
this._AvailableMediaIds.length = 0;
|
|
290
|
+
}
|
|
291
|
+
_HandleRoomUpdate(update) {
|
|
292
|
+
if (update.kind === 'Joined') {
|
|
293
|
+
assert(this._AvailableMediaIds.length === 0, 'left over media ids');
|
|
294
|
+
this._AvailableMediaIds.push(...update.media_ids);
|
|
295
|
+
this._HandleRoomJoined();
|
|
296
|
+
for (const peer of update.room.peers) {
|
|
297
|
+
this._HandlePeerJoined(peer);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else if (update.kind === 'PeerJoined') {
|
|
301
|
+
this._HandlePeerJoined(update.peer);
|
|
302
|
+
}
|
|
303
|
+
else if (update.kind === 'PeerLeft') {
|
|
304
|
+
this._HandlePeerLeft(update.peer_id);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
_HandleRoomJoined() {
|
|
308
|
+
for (const [capture, entry] of this._Captures) {
|
|
309
|
+
if (this._AvailableMediaIds.length === 0 ||
|
|
310
|
+
this.mainConnection === undefined) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
entry.media = {
|
|
314
|
+
connectionId: this.mainConnection.id,
|
|
315
|
+
mediaId: this._AvailableMediaIds.shift(),
|
|
316
|
+
};
|
|
317
|
+
if (capture instanceof AudioCapture) {
|
|
318
|
+
capture.start(this._Connection, entry.media, entry.uid);
|
|
319
|
+
}
|
|
320
|
+
if (capture instanceof VideoCapture) {
|
|
321
|
+
// @TODO Check if it needs implementation
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
_HandlePeerUpdate(update) {
|
|
326
|
+
if (update.kind === 'MediaStarted') {
|
|
327
|
+
this._HandleMediaStart(update.peer_id, update.media);
|
|
328
|
+
}
|
|
329
|
+
else if (update.kind === 'MediaStopped') {
|
|
330
|
+
this._HandleMediaStopped(update.peer_id, update.media_id);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
_HandlePeerJoined(peer) {
|
|
334
|
+
if (!this._Peers.has(peer.id)) {
|
|
335
|
+
this._Peers.set(peer.id, { mediaIds: new Map() });
|
|
336
|
+
}
|
|
337
|
+
for (const media of peer.medias) {
|
|
338
|
+
this._HandleMediaStart(peer.id, media);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
_HandlePeerLeft(peerId) {
|
|
342
|
+
const entry = this._Peers.get(peerId);
|
|
343
|
+
if (entry === undefined)
|
|
344
|
+
return;
|
|
345
|
+
for (const mediaId of entry.mediaIds.keys()) {
|
|
346
|
+
this._HandleMediaStopped(peerId, mediaId);
|
|
347
|
+
}
|
|
348
|
+
this._Peers.delete(peerId);
|
|
349
|
+
}
|
|
350
|
+
_HandleMediaStart(peerId, media) {
|
|
351
|
+
var _a, _b;
|
|
352
|
+
if (this.mainConnection === undefined)
|
|
353
|
+
return;
|
|
354
|
+
const peer = this._Peers.get(peerId);
|
|
355
|
+
if (peer === undefined ||
|
|
356
|
+
(media.properties.kind !== 'audio' && media.properties.kind !== 'video')) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const uid = String((_a = media.properties.uid) !== null && _a !== void 0 ? _a : generateUUID());
|
|
360
|
+
media.properties.uid = uid; // feed the uid back, so it can be seen be seen down the chain.
|
|
361
|
+
const entry = (_b = this._Playbacks.get(uid)) !== null && _b !== void 0 ? _b : {
|
|
362
|
+
media: undefined,
|
|
363
|
+
playback: undefined,
|
|
364
|
+
};
|
|
365
|
+
this._Playbacks.set(uid, entry);
|
|
366
|
+
peer.mediaIds.set(media.id, uid);
|
|
367
|
+
entry.media = {
|
|
368
|
+
connectionId: this.mainConnection.id,
|
|
369
|
+
mediaId: media.id,
|
|
370
|
+
};
|
|
371
|
+
if (entry.playback !== undefined) {
|
|
372
|
+
if (entry.playback instanceof AudioPlayback) {
|
|
373
|
+
entry.playback.start(entry.media);
|
|
374
|
+
}
|
|
375
|
+
if (entry.playback instanceof VideoPlayback) {
|
|
376
|
+
logger.debug(['Video'], '_HandleMediaStart() VideoPlayback');
|
|
377
|
+
this.mainConnection.startRemoteVideo(entry.media.mediaId).then();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
_HandleMediaStopped(peerId, mediaId) {
|
|
382
|
+
var _a;
|
|
383
|
+
const peer = this._Peers.get(peerId);
|
|
384
|
+
if (peer === undefined)
|
|
385
|
+
return;
|
|
386
|
+
const uid = peer === null || peer === void 0 ? void 0 : peer.mediaIds.get(mediaId);
|
|
387
|
+
if (uid === undefined)
|
|
388
|
+
return;
|
|
389
|
+
const entry = this._Playbacks.get(uid);
|
|
390
|
+
if (entry === undefined)
|
|
391
|
+
return;
|
|
392
|
+
if (entry.media !== undefined && entry.playback !== undefined) {
|
|
393
|
+
if (entry.playback instanceof AudioPlayback) {
|
|
394
|
+
entry.playback.stop(entry.media);
|
|
395
|
+
}
|
|
396
|
+
if (entry.playback instanceof VideoPlayback) {
|
|
397
|
+
logger.debug(['Video', '_HandleMediaStopped() VideoPlayback']);
|
|
398
|
+
(_a = this.mainConnection) === null || _a === void 0 ? void 0 : _a.stopRemoteVideo(entry.media.mediaId);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
entry.media = undefined;
|
|
402
|
+
peer.mediaIds.delete(mediaId);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Result } from '@4players/odin-common';
|
|
2
|
+
import { Token } from './token';
|
|
3
|
+
import { Transport } from './index';
|
|
4
|
+
import { RpcConnection } from './rpcConnection';
|
|
5
|
+
export type DatagramHandler = (connectionId: number, datagram: Uint8Array) => void;
|
|
6
|
+
export declare function createMainConnection(id: number, transport: Transport, address: string, onDatagram: DatagramHandler, signal: AbortSignal): Promise<Result<MainConnection>>;
|
|
7
|
+
export declare enum ConnectionStatus {
|
|
8
|
+
Connecting = 0,
|
|
9
|
+
Connected = 1,
|
|
10
|
+
Closed = 2
|
|
11
|
+
}
|
|
12
|
+
export interface MainConnection {
|
|
13
|
+
get id(): number;
|
|
14
|
+
get transport(): Transport;
|
|
15
|
+
get address(): string;
|
|
16
|
+
get status(): ConnectionStatus;
|
|
17
|
+
get closePromise(): Promise<'closed'>;
|
|
18
|
+
get closeSignal(): AbortSignal;
|
|
19
|
+
get closed(): boolean;
|
|
20
|
+
waitForConnected(): Promise<void>;
|
|
21
|
+
close(): void;
|
|
22
|
+
joinRoom(token: Token, roomId: string, userData: Uint8Array, position: [number, number, number]): Promise<Result<RpcConnection> | 'closed'>;
|
|
23
|
+
getReconnectToken(peerId: number): Promise<Result<Token>>;
|
|
24
|
+
healthCheck(): Promise<boolean>;
|
|
25
|
+
sendDatagram(datagram: Uint8Array): void;
|
|
26
|
+
startLocalVideo(mediaId: number, track: MediaStreamTrack): void;
|
|
27
|
+
stopLocalVideo(mediaId: number): void;
|
|
28
|
+
startRemoteVideo(mediaId: number): Promise<MediaStreamTrack>;
|
|
29
|
+
stopRemoteVideo(mediaId: number): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable no-dupe-class-members */
|
|
2
|
+
import { logger, Transport } from './index';
|
|
3
|
+
import { WebRtcMainConnection } from './webrtc/mainConnection';
|
|
4
|
+
import { H3MainConnection } from './h3/mainConnection';
|
|
5
|
+
export function createMainConnection(id, transport, address, onDatagram, signal) {
|
|
6
|
+
logger.log(['Connection'], 'createMainConnection() ', transport, address);
|
|
7
|
+
switch (transport) {
|
|
8
|
+
case Transport.H3:
|
|
9
|
+
return H3MainConnection.create(id, address, onDatagram, signal);
|
|
10
|
+
case Transport.WebRTC:
|
|
11
|
+
return WebRtcMainConnection.create(id, address, onDatagram, signal);
|
|
12
|
+
default:
|
|
13
|
+
throw new Error(`transport ${transport} is not supported`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export var ConnectionStatus;
|
|
17
|
+
(function (ConnectionStatus) {
|
|
18
|
+
ConnectionStatus[ConnectionStatus["Connecting"] = 0] = "Connecting";
|
|
19
|
+
ConnectionStatus[ConnectionStatus["Connected"] = 1] = "Connected";
|
|
20
|
+
ConnectionStatus[ConnectionStatus["Closed"] = 2] = "Closed";
|
|
21
|
+
})(ConnectionStatus || (ConnectionStatus = {}));
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Backend, Strand } from '@4players/odin-common';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export type Activity = Backend.Activity;
|
|
2
|
+
import { CaptureSink, PlaybackId, PlaybackWorker } from '../worker/common';
|
|
3
|
+
import { AudioCapture } from './medias/audio-capture';
|
|
4
|
+
import { VideoCapture } from './medias/video-capture';
|
|
5
|
+
import { AudioPlayback } from './medias/audio-playback';
|
|
7
6
|
export type CreateAudioPlaybackParameters = Backend.CreateAudioPlaybackParameters;
|
|
8
7
|
export type CreateAudioCaptureParameters = Backend.CreateAudioCaptureParameters & {
|
|
9
8
|
readonly device?: Device;
|
|
@@ -31,30 +30,30 @@ export declare class AudioContextCollection {
|
|
|
31
30
|
release(audioContext: BaseAudioContext): Promise<void>;
|
|
32
31
|
close(): void;
|
|
33
32
|
}
|
|
34
|
-
export declare class
|
|
33
|
+
export declare class MediaController {
|
|
35
34
|
readonly audioContexts: AudioContextCollection;
|
|
36
35
|
readonly sink: CaptureSink;
|
|
37
36
|
playbackWorker: PlaybackWorker | undefined;
|
|
38
37
|
globalVolume: number;
|
|
39
38
|
playbacks: Map<string, {
|
|
40
39
|
id: GlobalMediaId | undefined;
|
|
41
|
-
volume: Volume;
|
|
40
|
+
volume: Backend.Volume;
|
|
42
41
|
playback: AudioPlayback;
|
|
43
42
|
}>;
|
|
44
43
|
setPlaybackStrand: Strand;
|
|
45
|
-
create(audioContexts: AudioContextCollection, sink: CaptureSink): Promise<
|
|
44
|
+
create(audioContexts: AudioContextCollection, sink: CaptureSink): Promise<MediaController>;
|
|
46
45
|
constructor(audioContexts: AudioContextCollection, sink: CaptureSink);
|
|
47
46
|
receivePacket(connectionId: number, packet: Uint8Array): void;
|
|
48
47
|
createAudioPlayback(parameters: CreateAudioPlaybackParameters): Promise<AudioPlayback>;
|
|
49
48
|
createAudioCapture(parameters: CreateAudioCaptureParameters): Promise<AudioCapture>;
|
|
50
|
-
|
|
51
|
-
playbackSetDevice(device
|
|
49
|
+
createVideoCapture(ms: MediaStream, customType?: string): Promise<VideoCapture>;
|
|
50
|
+
playbackSetDevice(device?: Device): Promise<void>;
|
|
52
51
|
playbackSetGlobalVolume(value: Backend.Volume): void;
|
|
53
52
|
playbackStart(uid: string, id: GlobalMediaId): void;
|
|
54
53
|
playbackStop(uid: string, id: GlobalMediaId): void;
|
|
55
|
-
playbackGetActivity(uid: string): Activity;
|
|
56
|
-
playbackSetVolume(uid: string, volume: Volume): void;
|
|
57
|
-
playbackGetVolume(uid: string): Volume;
|
|
54
|
+
playbackGetActivity(uid: string): Backend.Activity;
|
|
55
|
+
playbackSetVolume(uid: string, volume: Backend.Volume): void;
|
|
56
|
+
playbackGetVolume(uid: string): Backend.Volume;
|
|
58
57
|
closePlayback(uid: string): void;
|
|
59
58
|
close(): void;
|
|
60
59
|
}
|
|
@@ -65,38 +64,3 @@ export declare class Device implements Backend.Device {
|
|
|
65
64
|
get type(): "AudioPlayback" | "AudioCapture";
|
|
66
65
|
get name(): string;
|
|
67
66
|
}
|
|
68
|
-
export declare class AudioPlayback implements Backend.AudioPlayback {
|
|
69
|
-
readonly controller: AudioController;
|
|
70
|
-
readonly uid: Backend.UID;
|
|
71
|
-
get volume(): Backend.Volume;
|
|
72
|
-
get activity(): Backend.Activity;
|
|
73
|
-
constructor(controller: AudioController, uid: Backend.UID);
|
|
74
|
-
start(id: GlobalMediaId): void;
|
|
75
|
-
stop(id: GlobalMediaId): void;
|
|
76
|
-
setVolume(value: Backend.Volume): void;
|
|
77
|
-
close(): void;
|
|
78
|
-
}
|
|
79
|
-
export declare class AudioCapture implements Backend.AudioCapture {
|
|
80
|
-
readonly controller: AudioController;
|
|
81
|
-
private _Capture;
|
|
82
|
-
private readonly _Medias;
|
|
83
|
-
private _Vad;
|
|
84
|
-
private _Apm;
|
|
85
|
-
private _Volume;
|
|
86
|
-
private _deviceParameters?;
|
|
87
|
-
get vad(): Backend.VadConfig;
|
|
88
|
-
get apm(): Backend.ApmConfig;
|
|
89
|
-
get volume(): Backend.Volume;
|
|
90
|
-
get activity(): import("@4players/odin-plugin-web-worker").Activity;
|
|
91
|
-
get speechProbability(): number;
|
|
92
|
-
constructor(controller: AudioController, parameters: CreateAudioCaptureParameters);
|
|
93
|
-
start(room: RoomConnection, media: GlobalMediaId, uid: Backend.UID): void;
|
|
94
|
-
stop(room: RoomConnection, media: GlobalMediaId): void;
|
|
95
|
-
setVad(value: Backend.VadConfig): void;
|
|
96
|
-
setApm(config: Backend.ApmConfig): Promise<void>;
|
|
97
|
-
setDevice(parameters: DeviceParameters): Promise<import("@4players/odin-common").Success<void> | undefined>;
|
|
98
|
-
setVolume(value: Backend.Volume): void;
|
|
99
|
-
close(): void;
|
|
100
|
-
_UpdateMedias(): Promise<void>;
|
|
101
|
-
}
|
|
102
|
-
//# sourceMappingURL=audioController.d.ts.map
|