@vkontakte/media-streaming 1.0.1-dev.7c4e0d2.0 → 1.0.1-dev.7e4da8a.0
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/{esnext.cjs → media-streaming.cjs} +249 -156
- package/media-streaming.esm.js +761 -0
- package/package.json +9 -9
- package/types/MediaConstraints.d.ts +8 -0
- package/types/MediaError.d.ts +4 -0
- package/types/ScreenConstraints.d.ts +5 -0
- package/types/WebRTCStreamer.d.ts +50 -0
- package/types/constants.d.ts +31 -0
- package/types/env.d.ts +1 -0
- package/types/index.d.ts +12 -0
- package/types/types.d.ts +71 -0
- package/types/utils.d.ts +22 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @vkontakte/media-streaming v1.0.1-dev.
|
|
3
|
-
*
|
|
2
|
+
* @vkontakte/media-streaming v1.0.1-dev.7e4da8a.0
|
|
3
|
+
* Fri, 07 Aug 2026 10:59:00 GMT
|
|
4
4
|
*/
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -56,18 +56,31 @@ __export(exports_src, {
|
|
|
56
56
|
WebRTCStreamer: () => WebRTCStreamer,
|
|
57
57
|
VERSION: () => VERSION,
|
|
58
58
|
StreamerError: () => StreamerError,
|
|
59
|
+
PermissionName: () => PermissionName,
|
|
60
|
+
MediaUtils: () => MediaUtils,
|
|
59
61
|
MediaErrorType: () => MediaErrorType
|
|
60
62
|
});
|
|
61
63
|
module.exports = __toCommonJS(exports_src);
|
|
62
64
|
|
|
63
|
-
// src/
|
|
64
|
-
|
|
65
|
+
// src/MediaError.ts
|
|
66
|
+
class StreamerMediaError extends Error {
|
|
67
|
+
constructor(name, message) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.name = name;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
// src/constants.ts
|
|
66
74
|
var DEFAULT_STUN_SERVERS = [{ urls: ["stun:videostun.mycdn.me:19302"] }];
|
|
67
75
|
var DEFAULT_WS_SERVER = "wss://ovsu.mycdn.me/publish";
|
|
68
76
|
var WS_CLOSE_CODE = 1000;
|
|
69
77
|
var DEFAULT_FRAME_RATE = 15;
|
|
70
78
|
var SCREEN_SHARE_CONTENT_TEXTHINT = "text";
|
|
79
|
+
var PermissionName;
|
|
80
|
+
((PermissionName2) => {
|
|
81
|
+
PermissionName2["DISPLAY_MEDIA"] = "display_media";
|
|
82
|
+
PermissionName2["USER_MEDIA"] = "user_media";
|
|
83
|
+
})(PermissionName ||= {});
|
|
71
84
|
var MediaErrorType;
|
|
72
85
|
((MediaErrorType2) => {
|
|
73
86
|
MediaErrorType2["UNKNOWN"] = "unknown";
|
|
@@ -84,8 +97,6 @@ var StreamerError;
|
|
|
84
97
|
StreamerError2["PEERCONNECTION"] = "peerconnection";
|
|
85
98
|
StreamerError2["CONSTRAINTS"] = "constraints";
|
|
86
99
|
})(StreamerError ||= {});
|
|
87
|
-
// src/WebRTCStreamer.ts
|
|
88
|
-
var import_videoplayer_shared = require("@vkontakte/videoplayer-shared");
|
|
89
100
|
|
|
90
101
|
// src/MediaConstraints.ts
|
|
91
102
|
class MediaConstraints {
|
|
@@ -121,14 +132,6 @@ class MediaConstraints {
|
|
|
121
132
|
}
|
|
122
133
|
}
|
|
123
134
|
|
|
124
|
-
// src/MediaError.ts
|
|
125
|
-
class MediaError2 extends Error {
|
|
126
|
-
constructor(name, message) {
|
|
127
|
-
super(message);
|
|
128
|
-
this.name = name;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
135
|
// src/utils.ts
|
|
133
136
|
var getWindow = () => {
|
|
134
137
|
return globalThis;
|
|
@@ -149,29 +152,38 @@ var getSafariVersion = (userAgent) => {
|
|
|
149
152
|
const version = parseInt(versionMatch[1], 10);
|
|
150
153
|
return isNaN(version) ? undefined : version;
|
|
151
154
|
};
|
|
152
|
-
var enumerateDevices = async () =>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
155
|
+
var enumerateDevices = async () => {
|
|
156
|
+
const devices = await getWindow().navigator.mediaDevices.enumerateDevices();
|
|
157
|
+
return {
|
|
158
|
+
cameras: devices.filter((d) => d.kind === "videoinput"),
|
|
159
|
+
microphones: devices.filter((d) => d.kind === "audioinput")
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
var getUserStream = (config) => {
|
|
163
|
+
const constraints = new MediaConstraints(config).getNative();
|
|
164
|
+
return getWindow().navigator.mediaDevices.getUserMedia(constraints).catch((e) => {
|
|
165
|
+
if (e instanceof Error) {
|
|
166
|
+
switch (e.name) {
|
|
167
|
+
case "PermissionDismissedError":
|
|
168
|
+
case "PermissionDeniedError":
|
|
169
|
+
case "SecurityError":
|
|
170
|
+
case "NotAllowedError":
|
|
171
|
+
case "DOMException":
|
|
172
|
+
throw new StreamerMediaError(e.name, "permission" /* PERMISSION */);
|
|
173
|
+
case "OverconstrainedError":
|
|
174
|
+
case "NotFoundError":
|
|
175
|
+
case "TypeError":
|
|
176
|
+
throw new StreamerMediaError(e.name, "unknown" /* UNKNOWN */);
|
|
177
|
+
case "AbortError":
|
|
178
|
+
case "NotReadableError":
|
|
179
|
+
throw new StreamerMediaError(e.name, "access" /* ACCESS */);
|
|
180
|
+
default:
|
|
181
|
+
throw new StreamerMediaError(e.name, "unknown" /* UNKNOWN */);
|
|
182
|
+
}
|
|
171
183
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
184
|
+
throw new Error("unknown");
|
|
185
|
+
});
|
|
186
|
+
};
|
|
175
187
|
var getDisplayMedia = (constraints) => getWindow().navigator.mediaDevices.getDisplayMedia(constraints.getNative()).catch((e) => {
|
|
176
188
|
if (e instanceof Error) {
|
|
177
189
|
switch (e.name) {
|
|
@@ -205,7 +217,7 @@ var serializeConfig = (cfg) => {
|
|
|
205
217
|
key: cfg.streamKey,
|
|
206
218
|
...cfg.audioOnly && { audioOnly: true },
|
|
207
219
|
...cfg.lockOrientation && { lockOrientation: true },
|
|
208
|
-
...cfg.
|
|
220
|
+
...cfg.mediaConfig && { mediaConfig: cfg.mediaConfig },
|
|
209
221
|
...cfg.screenShare && { screenShare: omitKeys(cfg.screenShare, ["onEnded"]) }
|
|
210
222
|
};
|
|
211
223
|
};
|
|
@@ -217,6 +229,11 @@ var serializeMediaDevices = (devices) => {
|
|
|
217
229
|
}));
|
|
218
230
|
};
|
|
219
231
|
|
|
232
|
+
// src/env.ts
|
|
233
|
+
var VERSION = "1.0.1-dev.7e4da8a.0";
|
|
234
|
+
// src/WebRTCStreamer.ts
|
|
235
|
+
var import_videoplayer_shared = require("@vkontakte/videoplayer-shared");
|
|
236
|
+
|
|
220
237
|
// src/ScreenConstraints.ts
|
|
221
238
|
class ScreenConstraints extends MediaConstraints {
|
|
222
239
|
constructor({ width, height, frameRate = DEFAULT_FRAME_RATE }) {
|
|
@@ -246,20 +263,20 @@ class ScreenConstraints extends MediaConstraints {
|
|
|
246
263
|
// src/WebRTCStreamer.ts
|
|
247
264
|
class WebRTCStreamer {
|
|
248
265
|
config;
|
|
249
|
-
messagesQueue = [];
|
|
250
|
-
ws;
|
|
251
|
-
peerConnection;
|
|
252
|
-
stream;
|
|
253
|
-
screenShareTrack = null;
|
|
254
|
-
connected = false;
|
|
255
|
-
destroying = false;
|
|
256
|
-
cameraId;
|
|
257
|
-
microphoneId;
|
|
258
|
-
muted = false;
|
|
266
|
+
#messagesQueue = [];
|
|
267
|
+
#ws;
|
|
268
|
+
#peerConnection;
|
|
269
|
+
#stream;
|
|
270
|
+
#screenShareTrack = null;
|
|
271
|
+
#connected = false;
|
|
272
|
+
#destroying = false;
|
|
273
|
+
#cameraId;
|
|
274
|
+
#microphoneId;
|
|
275
|
+
#muted = false;
|
|
259
276
|
static notDestroying(_target, _propertyKey, descriptor) {
|
|
260
277
|
const original = descriptor.value;
|
|
261
278
|
descriptor.value = function(...args) {
|
|
262
|
-
if (this
|
|
279
|
+
if (this.#destroying) {
|
|
263
280
|
return;
|
|
264
281
|
}
|
|
265
282
|
return original.apply(this, args);
|
|
@@ -271,23 +288,26 @@ class WebRTCStreamer {
|
|
|
271
288
|
}
|
|
272
289
|
callback(name, ...args) {
|
|
273
290
|
const fn = this.config.callbacks[name];
|
|
274
|
-
if (fn && !this
|
|
291
|
+
if (fn && !this.#destroying) {
|
|
275
292
|
fn?.(...args);
|
|
276
293
|
}
|
|
277
294
|
}
|
|
295
|
+
get connected() {
|
|
296
|
+
return this.#connected;
|
|
297
|
+
}
|
|
278
298
|
async init() {
|
|
299
|
+
const { cameras, microphones } = await enumerateDevices();
|
|
279
300
|
this.tracerLog("init", {
|
|
280
301
|
cfg: serializeConfig(this.config),
|
|
281
|
-
d: serializeMediaDevices(
|
|
302
|
+
d: serializeMediaDevices([...cameras, ...microphones])
|
|
282
303
|
});
|
|
283
304
|
let permissionName = "user_media" /* USER_MEDIA */;
|
|
284
|
-
const { audioOnly,
|
|
305
|
+
const { audioOnly, mediaConfig, screenShare } = this.config;
|
|
285
306
|
try {
|
|
286
|
-
|
|
307
|
+
this.#stream = await getUserStream(mediaConfig ?? {
|
|
287
308
|
audio: true,
|
|
288
309
|
video: !screenShare && !audioOnly
|
|
289
310
|
});
|
|
290
|
-
this.stream = await getUserMedia(constraints.getNative());
|
|
291
311
|
if (!audioOnly && screenShare) {
|
|
292
312
|
permissionName = "display_media" /* DISPLAY_MEDIA */;
|
|
293
313
|
const screenShareTrack = await this.createScreenShareStream(screenShare);
|
|
@@ -298,18 +318,17 @@ class WebRTCStreamer {
|
|
|
298
318
|
frameRate: { exact: frameRate }
|
|
299
319
|
});
|
|
300
320
|
} catch (e) {
|
|
301
|
-
this.
|
|
302
|
-
this.callback("onError", "constraints" /* CONSTRAINTS */);
|
|
321
|
+
this.handleScreenShareConstraintsError(frameRate);
|
|
303
322
|
}
|
|
304
|
-
this
|
|
323
|
+
this.#stream.addTrack(screenShareTrack);
|
|
305
324
|
}
|
|
306
|
-
this
|
|
325
|
+
this.#screenShareTrack = screenShareTrack;
|
|
307
326
|
}
|
|
308
|
-
this.tracerLog("streamChanged", serializeStream(this
|
|
309
|
-
this.callback("onStreamChanged", this
|
|
327
|
+
this.tracerLog("streamChanged", serializeStream(this.#stream));
|
|
328
|
+
this.callback("onStreamChanged", this.#stream);
|
|
310
329
|
} catch (err) {
|
|
311
|
-
if (err instanceof
|
|
312
|
-
this.tracerLog("permissionFailed", { name: permissionName, msg: err.message, code: err.
|
|
330
|
+
if (err instanceof StreamerMediaError) {
|
|
331
|
+
this.tracerLog("permissionFailed", { name: permissionName, msg: err.message, code: err.name });
|
|
313
332
|
this.callback("onPermissionFailed", permissionName, err);
|
|
314
333
|
} else {
|
|
315
334
|
this.tracerLog("permissionFailed", { name: permissionName });
|
|
@@ -319,8 +338,9 @@ class WebRTCStreamer {
|
|
|
319
338
|
}
|
|
320
339
|
async connect() {
|
|
321
340
|
this.tracerLog("connect");
|
|
341
|
+
this.callback("onConnecting");
|
|
322
342
|
this.openSocket();
|
|
323
|
-
if (!this
|
|
343
|
+
if (!this.#peerConnection) {
|
|
324
344
|
await this.createPeerConnection();
|
|
325
345
|
}
|
|
326
346
|
}
|
|
@@ -330,59 +350,60 @@ class WebRTCStreamer {
|
|
|
330
350
|
if (audioOnly) {
|
|
331
351
|
return;
|
|
332
352
|
}
|
|
333
|
-
this
|
|
334
|
-
const
|
|
335
|
-
audio: this
|
|
336
|
-
deviceId: this
|
|
353
|
+
this.#cameraId = deviceId;
|
|
354
|
+
const newStream = await getUserStream({
|
|
355
|
+
audio: this.#microphoneId ? {
|
|
356
|
+
deviceId: this.#microphoneId
|
|
337
357
|
} : true,
|
|
338
358
|
video: {
|
|
339
|
-
deviceId: this
|
|
359
|
+
deviceId: this.#cameraId
|
|
340
360
|
}
|
|
341
361
|
});
|
|
342
|
-
const newStream = await getUserMedia(constraints.getNative());
|
|
343
362
|
this.replaceStream(newStream);
|
|
344
|
-
if (this
|
|
363
|
+
if (this.#muted) {
|
|
345
364
|
this.setMicMuted(true);
|
|
346
365
|
}
|
|
347
366
|
}
|
|
348
367
|
async switchMicrophone(deviceId) {
|
|
349
368
|
this.tracerLog("switchMicrophone", { id: deviceId });
|
|
350
|
-
this
|
|
351
|
-
const
|
|
369
|
+
this.#microphoneId = deviceId;
|
|
370
|
+
const newStream = await getUserStream({
|
|
352
371
|
audio: {
|
|
353
|
-
deviceId: this
|
|
372
|
+
deviceId: this.#microphoneId
|
|
354
373
|
},
|
|
355
|
-
video: this
|
|
356
|
-
deviceId: this
|
|
374
|
+
video: this.#screenShareTrack ? false : this.#cameraId ? {
|
|
375
|
+
deviceId: this.#cameraId
|
|
357
376
|
} : true
|
|
358
377
|
});
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
newStream.addTrack(this.screenShareTrack);
|
|
378
|
+
if (this.#screenShareTrack) {
|
|
379
|
+
newStream.addTrack(this.#screenShareTrack);
|
|
362
380
|
}
|
|
363
381
|
this.replaceStream(newStream, true);
|
|
364
|
-
if (this
|
|
382
|
+
if (this.#muted) {
|
|
365
383
|
this.setMicMuted(true);
|
|
366
384
|
}
|
|
367
385
|
}
|
|
368
386
|
async enableScreenShare(config) {
|
|
369
387
|
this.tracerLog("enableScreenShare", omitKeys(config, ["onEnded"]));
|
|
370
|
-
const
|
|
371
|
-
audio: this
|
|
388
|
+
const newStream = await getUserStream({
|
|
389
|
+
audio: this.#microphoneId ? { deviceId: this.#microphoneId } : true,
|
|
372
390
|
video: false
|
|
373
391
|
});
|
|
374
|
-
const newStream = await getUserMedia(constraints.getNative());
|
|
375
392
|
const screenShareTrack = await this.createScreenShareStream(config);
|
|
376
393
|
if (screenShareTrack) {
|
|
377
394
|
const { frameRate = DEFAULT_FRAME_RATE } = config;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
395
|
+
try {
|
|
396
|
+
await screenShareTrack.applyConstraints({
|
|
397
|
+
frameRate: { exact: frameRate }
|
|
398
|
+
});
|
|
399
|
+
} catch (e) {
|
|
400
|
+
this.handleScreenShareConstraintsError(frameRate);
|
|
401
|
+
}
|
|
381
402
|
newStream.addTrack(screenShareTrack);
|
|
382
403
|
}
|
|
383
|
-
this
|
|
404
|
+
this.#screenShareTrack = screenShareTrack;
|
|
384
405
|
this.replaceStream(newStream);
|
|
385
|
-
if (this
|
|
406
|
+
if (this.#muted) {
|
|
386
407
|
this.setMicMuted(true);
|
|
387
408
|
}
|
|
388
409
|
}
|
|
@@ -391,37 +412,90 @@ class WebRTCStreamer {
|
|
|
391
412
|
if (cameraDeviceId) {
|
|
392
413
|
await this.switchCamera(cameraDeviceId);
|
|
393
414
|
} else {
|
|
394
|
-
const
|
|
395
|
-
const defaultCamera =
|
|
415
|
+
const { cameras } = await enumerateDevices();
|
|
416
|
+
const defaultCamera = cameras[0];
|
|
396
417
|
if (defaultCamera) {
|
|
397
418
|
await this.switchCamera(defaultCamera.deviceId);
|
|
398
419
|
}
|
|
399
420
|
}
|
|
400
421
|
}
|
|
422
|
+
async switchMediaDevices({
|
|
423
|
+
cameraId,
|
|
424
|
+
microphoneId,
|
|
425
|
+
screenShare
|
|
426
|
+
}) {
|
|
427
|
+
if (cameraId === undefined && microphoneId === undefined && screenShare === undefined) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
this.tracerLog("switchMediaDevices", {
|
|
431
|
+
...cameraId !== undefined && { cam: cameraId },
|
|
432
|
+
...microphoneId !== undefined && { mic: microphoneId },
|
|
433
|
+
...screenShare !== undefined && { ss: screenShare === false ? false : omitKeys(screenShare, ["onEnded"]) }
|
|
434
|
+
});
|
|
435
|
+
const { audioOnly } = this.config;
|
|
436
|
+
const changingScreenShare = screenShare !== undefined;
|
|
437
|
+
const keepScreenShare = !changingScreenShare && Boolean(this.#screenShareTrack);
|
|
438
|
+
let audio = this.#microphoneId ? { deviceId: this.#microphoneId } : true;
|
|
439
|
+
let video = this.#cameraId ? { deviceId: this.#cameraId } : true;
|
|
440
|
+
if (microphoneId) {
|
|
441
|
+
this.#microphoneId = microphoneId;
|
|
442
|
+
audio = { deviceId: microphoneId };
|
|
443
|
+
} else if (microphoneId === false) {
|
|
444
|
+
audio = false;
|
|
445
|
+
}
|
|
446
|
+
if (audioOnly || cameraId === false) {
|
|
447
|
+
video = false;
|
|
448
|
+
} else if (cameraId) {
|
|
449
|
+
this.#cameraId = cameraId;
|
|
450
|
+
video = screenShare || keepScreenShare ? false : { deviceId: cameraId };
|
|
451
|
+
}
|
|
452
|
+
const newStream = await getUserStream({ audio, video });
|
|
453
|
+
if (screenShare) {
|
|
454
|
+
const screenShareTrack = await this.createScreenShareStream(screenShare);
|
|
455
|
+
if (screenShareTrack) {
|
|
456
|
+
const { frameRate = DEFAULT_FRAME_RATE } = screenShare;
|
|
457
|
+
try {
|
|
458
|
+
await screenShareTrack.applyConstraints({
|
|
459
|
+
frameRate: { exact: frameRate }
|
|
460
|
+
});
|
|
461
|
+
} catch (e) {
|
|
462
|
+
this.handleScreenShareConstraintsError(frameRate);
|
|
463
|
+
}
|
|
464
|
+
newStream.addTrack(screenShareTrack);
|
|
465
|
+
}
|
|
466
|
+
this.#screenShareTrack = screenShareTrack;
|
|
467
|
+
} else if (keepScreenShare && this.#screenShareTrack) {
|
|
468
|
+
newStream.addTrack(this.#screenShareTrack);
|
|
469
|
+
}
|
|
470
|
+
this.replaceStream(newStream, keepScreenShare);
|
|
471
|
+
if (this.#muted) {
|
|
472
|
+
this.setMicMuted(true);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
401
475
|
setMicMuted(muted) {
|
|
402
476
|
this.tracerLog("setMicMuted", { m: muted });
|
|
403
|
-
this
|
|
404
|
-
this
|
|
477
|
+
this.#muted = muted;
|
|
478
|
+
this.#stream?.getAudioTracks().forEach((track) => {
|
|
405
479
|
track.enabled = !muted;
|
|
406
480
|
});
|
|
407
481
|
}
|
|
408
482
|
setCameraEnabled(enabled) {
|
|
409
483
|
this.tracerLog("setCameraEnabled", { on: enabled });
|
|
410
|
-
this
|
|
484
|
+
this.#stream?.getVideoTracks().forEach((track) => {
|
|
411
485
|
track.enabled = enabled;
|
|
412
486
|
});
|
|
413
487
|
}
|
|
414
488
|
destroy() {
|
|
415
|
-
this
|
|
489
|
+
this.#destroying = true;
|
|
416
490
|
this.tracerLog("destroy");
|
|
417
491
|
this.disconnect();
|
|
418
|
-
this
|
|
419
|
-
this
|
|
420
|
-
this
|
|
421
|
-
if (this
|
|
422
|
-
this
|
|
423
|
-
this
|
|
424
|
-
this
|
|
492
|
+
this.#cameraId = undefined;
|
|
493
|
+
this.#microphoneId = undefined;
|
|
494
|
+
this.#muted = false;
|
|
495
|
+
if (this.#stream) {
|
|
496
|
+
this.#stream.getTracks().forEach((track) => track.stop());
|
|
497
|
+
this.#stream = undefined;
|
|
498
|
+
this.#screenShareTrack = null;
|
|
425
499
|
}
|
|
426
500
|
}
|
|
427
501
|
disconnect() {
|
|
@@ -433,26 +507,26 @@ class WebRTCStreamer {
|
|
|
433
507
|
}
|
|
434
508
|
}
|
|
435
509
|
replaceStream(stream, keepScreenShare = false) {
|
|
436
|
-
this
|
|
510
|
+
this.#stream?.getTracks().forEach((track) => {
|
|
437
511
|
const isScreenShare = track.contentHint === SCREEN_SHARE_CONTENT_TEXTHINT;
|
|
438
512
|
if (!isScreenShare || !keepScreenShare) {
|
|
439
513
|
track.stop();
|
|
440
514
|
if (isScreenShare) {
|
|
441
|
-
this
|
|
515
|
+
this.#screenShareTrack = null;
|
|
442
516
|
}
|
|
443
517
|
}
|
|
444
|
-
this
|
|
518
|
+
this.#stream?.removeTrack(track);
|
|
445
519
|
});
|
|
446
|
-
this
|
|
520
|
+
this.#stream = stream;
|
|
447
521
|
this.tracerLog("streamChanged", serializeStream(stream));
|
|
448
|
-
this.callback("onStreamChanged", this
|
|
449
|
-
this.replaceTracksInPeerConnection(this
|
|
522
|
+
this.callback("onStreamChanged", this.#stream);
|
|
523
|
+
this.replaceTracksInPeerConnection(this.#stream);
|
|
450
524
|
}
|
|
451
525
|
replaceTracksInPeerConnection(stream, keepScreenShare = false) {
|
|
452
|
-
if (!this
|
|
526
|
+
if (!this.#peerConnection) {
|
|
453
527
|
return;
|
|
454
528
|
}
|
|
455
|
-
this
|
|
529
|
+
this.#peerConnection.getTransceivers().forEach(({ sender }) => {
|
|
456
530
|
const { track } = sender;
|
|
457
531
|
if (track && (track.contentHint !== SCREEN_SHARE_CONTENT_TEXTHINT || !keepScreenShare)) {
|
|
458
532
|
track.stop();
|
|
@@ -465,7 +539,7 @@ class WebRTCStreamer {
|
|
|
465
539
|
});
|
|
466
540
|
}
|
|
467
541
|
get socketOpened() {
|
|
468
|
-
return this
|
|
542
|
+
return this.#ws?.readyState === WebSocket.OPEN;
|
|
469
543
|
}
|
|
470
544
|
async createScreenShareStream(screenShare) {
|
|
471
545
|
const { width, height, onEnded = null } = screenShare;
|
|
@@ -474,25 +548,25 @@ class WebRTCStreamer {
|
|
|
474
548
|
if (screenShareTrack) {
|
|
475
549
|
screenShareTrack.contentHint = SCREEN_SHARE_CONTENT_TEXTHINT;
|
|
476
550
|
screenShareTrack.onended = () => {
|
|
477
|
-
this
|
|
551
|
+
this.#screenShareTrack = null;
|
|
478
552
|
onEnded?.();
|
|
479
553
|
};
|
|
480
554
|
}
|
|
481
555
|
return screenShareTrack;
|
|
482
556
|
}
|
|
483
557
|
openSocket() {
|
|
484
|
-
if (!this
|
|
485
|
-
this
|
|
486
|
-
this
|
|
487
|
-
this
|
|
488
|
-
this
|
|
558
|
+
if (!this.#ws || this.#ws.readyState === WebSocket.CLOSED) {
|
|
559
|
+
this.#ws = new WebSocket(this.config.serverUrl ?? DEFAULT_WS_SERVER);
|
|
560
|
+
this.#ws.onopen = this.handleWSOpen;
|
|
561
|
+
this.#ws.onmessage = this.handleWSMessage;
|
|
562
|
+
this.#ws.onclose = this.handleWSClose;
|
|
489
563
|
}
|
|
490
564
|
}
|
|
491
565
|
handleWSOpen = () => {
|
|
492
566
|
this.sendMessageFromQueue();
|
|
493
567
|
};
|
|
494
568
|
handleWSMessage = (event) => {
|
|
495
|
-
if (this
|
|
569
|
+
if (this.#destroying || !this.#ws || this.#ws.readyState >= WebSocket.CLOSING) {
|
|
496
570
|
return;
|
|
497
571
|
}
|
|
498
572
|
const message = this.parseMessage(event.data);
|
|
@@ -510,26 +584,27 @@ class WebRTCStreamer {
|
|
|
510
584
|
};
|
|
511
585
|
handleWSClose = (event) => {
|
|
512
586
|
this.closePeerConnection();
|
|
513
|
-
if (!this
|
|
587
|
+
if (!this.#ws) {
|
|
514
588
|
return;
|
|
515
589
|
}
|
|
516
|
-
|
|
517
|
-
this
|
|
518
|
-
this
|
|
590
|
+
const isAbnormalClose = event.code > 1000;
|
|
591
|
+
this.#messagesQueue = [];
|
|
592
|
+
this.#connected = false;
|
|
593
|
+
this.#ws = undefined;
|
|
519
594
|
this.tracerLog("disconnected", { code: event.code });
|
|
520
|
-
this.callback("onDisconnected",
|
|
595
|
+
this.callback("onDisconnected", isAbnormalClose ? "connection" /* CONNECTION */ : undefined);
|
|
521
596
|
};
|
|
522
597
|
send(message) {
|
|
523
|
-
this
|
|
598
|
+
this.#messagesQueue.push(message);
|
|
524
599
|
if (this.socketOpened) {
|
|
525
600
|
this.sendMessageFromQueue();
|
|
526
601
|
}
|
|
527
602
|
}
|
|
528
603
|
sendMessageFromQueue() {
|
|
529
|
-
while (this
|
|
604
|
+
while (this.#messagesQueue.length > 0) {
|
|
530
605
|
if (this.socketOpened) {
|
|
531
|
-
const message = this
|
|
532
|
-
this
|
|
606
|
+
const message = this.#messagesQueue.shift();
|
|
607
|
+
this.#ws?.send(JSON.stringify(message));
|
|
533
608
|
}
|
|
534
609
|
}
|
|
535
610
|
}
|
|
@@ -555,10 +630,14 @@ class WebRTCStreamer {
|
|
|
555
630
|
}
|
|
556
631
|
}
|
|
557
632
|
handleAnswer(sdp) {
|
|
558
|
-
this
|
|
633
|
+
this.#peerConnection?.setRemoteDescription(new RTCSessionDescription({ type: "answer", sdp }));
|
|
559
634
|
}
|
|
560
635
|
handleCandidate(candidate) {
|
|
561
|
-
this
|
|
636
|
+
this.#peerConnection?.addIceCandidate(new RTCIceCandidate(candidate));
|
|
637
|
+
}
|
|
638
|
+
handleScreenShareConstraintsError(frameRate) {
|
|
639
|
+
this.tracerLog("error", { type: "constraints" /* CONSTRAINTS */, frameRate });
|
|
640
|
+
this.callback("onError", "constraints" /* CONSTRAINTS */);
|
|
562
641
|
}
|
|
563
642
|
handleError(err, message) {
|
|
564
643
|
if (["no_stream_data" /* NO_STREAM_DATA */, "peerconnection" /* PEERCONNECTION */].includes(err)) {
|
|
@@ -570,22 +649,27 @@ class WebRTCStreamer {
|
|
|
570
649
|
this.callback("onError", err, reason);
|
|
571
650
|
}
|
|
572
651
|
async createPeerConnection() {
|
|
573
|
-
this.peerConnection = new RTCPeerConnection({
|
|
574
|
-
iceServers: this.config.stunServers ?? DEFAULT_STUN_SERVERS,
|
|
575
|
-
rtcpMuxPolicy: "require",
|
|
576
|
-
bundlePolicy: "max-compat"
|
|
577
|
-
});
|
|
578
|
-
this.peerConnection.onicecandidate = this.handleRTCIceCandidate;
|
|
579
|
-
this.peerConnection.onsignalingstatechange = this.handleRTCSignalingStateChange;
|
|
580
|
-
this.peerConnection.oniceconnectionstatechange = this.handleRTCIceConnectionStateChange;
|
|
581
|
-
this.stream?.getTracks().forEach((track) => {
|
|
582
|
-
if (track.kind === "video") {
|
|
583
|
-
track.contentHint = "text";
|
|
584
|
-
}
|
|
585
|
-
this.stream && this.peerConnection?.addTrack(track, this.stream);
|
|
586
|
-
});
|
|
587
652
|
try {
|
|
588
|
-
|
|
653
|
+
this.#peerConnection = new RTCPeerConnection({
|
|
654
|
+
iceServers: this.config.stunServers ?? DEFAULT_STUN_SERVERS,
|
|
655
|
+
rtcpMuxPolicy: "require",
|
|
656
|
+
bundlePolicy: "max-compat"
|
|
657
|
+
});
|
|
658
|
+
this.#peerConnection.onicecandidate = this.handleRTCIceCandidate;
|
|
659
|
+
this.#peerConnection.onsignalingstatechange = this.handleRTCSignalingStateChange;
|
|
660
|
+
this.#peerConnection.oniceconnectionstatechange = this.handleRTCIceConnectionStateChange;
|
|
661
|
+
this.#stream?.getTracks().forEach((track) => {
|
|
662
|
+
if (track.kind === "video") {
|
|
663
|
+
track.contentHint = "text";
|
|
664
|
+
}
|
|
665
|
+
this.#stream && this.#peerConnection?.addTrack(track, this.#stream);
|
|
666
|
+
});
|
|
667
|
+
} catch (e) {
|
|
668
|
+
this.handleError("peerconnection" /* PEERCONNECTION */, "create peer connection failed");
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
try {
|
|
672
|
+
const offer = await this.#peerConnection.createOffer();
|
|
589
673
|
if (this.config.lockOrientation) {
|
|
590
674
|
offer.sdp = offer.sdp?.replace(/a=extmap:[0-9]+ urn:3gpp:video-orientation[\r\n]+/g, "");
|
|
591
675
|
}
|
|
@@ -608,12 +692,12 @@ class WebRTCStreamer {
|
|
|
608
692
|
}
|
|
609
693
|
};
|
|
610
694
|
handleRTCSignalingStateChange = () => {
|
|
611
|
-
if (!this
|
|
695
|
+
if (!this.#peerConnection) {
|
|
612
696
|
return;
|
|
613
697
|
}
|
|
614
|
-
switch (this
|
|
698
|
+
switch (this.#peerConnection.signalingState) {
|
|
615
699
|
case "have-local-offer":
|
|
616
|
-
const sdp = this
|
|
700
|
+
const sdp = this.#peerConnection.localDescription?.sdp;
|
|
617
701
|
this.send({
|
|
618
702
|
type: "INVITE",
|
|
619
703
|
inviteType: "OFFER",
|
|
@@ -628,10 +712,10 @@ class WebRTCStreamer {
|
|
|
628
712
|
}
|
|
629
713
|
};
|
|
630
714
|
handleRTCIceConnectionStateChange = () => {
|
|
631
|
-
if (!this
|
|
715
|
+
if (!this.#peerConnection) {
|
|
632
716
|
return;
|
|
633
717
|
}
|
|
634
|
-
switch (this
|
|
718
|
+
switch (this.#peerConnection.iceConnectionState) {
|
|
635
719
|
case "failed":
|
|
636
720
|
this.handleError("peerconnection" /* PEERCONNECTION */, "ice connection failed");
|
|
637
721
|
break;
|
|
@@ -639,7 +723,7 @@ class WebRTCStreamer {
|
|
|
639
723
|
this.disconnect();
|
|
640
724
|
break;
|
|
641
725
|
case "connected":
|
|
642
|
-
this
|
|
726
|
+
this.#connected = true;
|
|
643
727
|
this.tracerLog("connected");
|
|
644
728
|
this.callback("onConnected");
|
|
645
729
|
break;
|
|
@@ -647,22 +731,22 @@ class WebRTCStreamer {
|
|
|
647
731
|
};
|
|
648
732
|
async setDescription(description) {
|
|
649
733
|
try {
|
|
650
|
-
await this
|
|
734
|
+
await this.#peerConnection?.setLocalDescription(description);
|
|
651
735
|
} catch (e) {
|
|
652
736
|
this.handleError("peerconnection" /* PEERCONNECTION */, "set local description failed");
|
|
653
737
|
}
|
|
654
738
|
}
|
|
655
739
|
closePeerConnection() {
|
|
656
|
-
if (this
|
|
657
|
-
if (this
|
|
658
|
-
this
|
|
740
|
+
if (this.#peerConnection) {
|
|
741
|
+
if (this.#peerConnection.signalingState !== "closed") {
|
|
742
|
+
this.#peerConnection.close();
|
|
659
743
|
}
|
|
660
|
-
this
|
|
744
|
+
this.#peerConnection = undefined;
|
|
661
745
|
}
|
|
662
746
|
}
|
|
663
747
|
closeWSConnection() {
|
|
664
|
-
if (this
|
|
665
|
-
this
|
|
748
|
+
if (this.#ws && this.#ws.readyState < WebSocket.CLOSING) {
|
|
749
|
+
this.#ws.close(WS_CLOSE_CODE);
|
|
666
750
|
}
|
|
667
751
|
}
|
|
668
752
|
parseMessage(data) {
|
|
@@ -675,6 +759,9 @@ class WebRTCStreamer {
|
|
|
675
759
|
tracerLog(event, data) {
|
|
676
760
|
return this.config.tracer?.log(event, import_videoplayer_shared.flattenObject(data));
|
|
677
761
|
}
|
|
762
|
+
logStat(event, data) {
|
|
763
|
+
this.config.statisticsLogger?.log(event, data);
|
|
764
|
+
}
|
|
678
765
|
}
|
|
679
766
|
__legacyDecorateClassTS([
|
|
680
767
|
WebRTCStreamer.notDestroying
|
|
@@ -694,6 +781,9 @@ __legacyDecorateClassTS([
|
|
|
694
781
|
__legacyDecorateClassTS([
|
|
695
782
|
WebRTCStreamer.notDestroying
|
|
696
783
|
], WebRTCStreamer.prototype, "disableScreenShare", null);
|
|
784
|
+
__legacyDecorateClassTS([
|
|
785
|
+
WebRTCStreamer.notDestroying
|
|
786
|
+
], WebRTCStreamer.prototype, "switchMediaDevices", null);
|
|
697
787
|
__legacyDecorateClassTS([
|
|
698
788
|
WebRTCStreamer.notDestroying
|
|
699
789
|
], WebRTCStreamer.prototype, "setMicMuted", null);
|
|
@@ -704,6 +794,9 @@ __legacyDecorateClassTS([
|
|
|
704
794
|
WebRTCStreamer.notDestroying
|
|
705
795
|
], WebRTCStreamer.prototype, "destroy", null);
|
|
706
796
|
|
|
707
|
-
|
|
797
|
+
// src/index.ts
|
|
798
|
+
var MediaUtils = { enumerateDevices, getUserStream };
|
|
799
|
+
|
|
800
|
+
//# debugId=70F3C6815BAD3F6964756E2164756E21
|
|
708
801
|
|
|
709
|
-
//# sourceMappingURL=
|
|
802
|
+
//# sourceMappingURL=media-streaming.cjs.map
|