@vkontakte/media-streaming 1.0.1-dev.2e8c6c4.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.
@@ -0,0 +1,801 @@
1
+ /**
2
+ * @vkontakte/media-streaming v1.0.1-dev.2e8c6c4.0
3
+ * Wed, 05 Aug 2026 12:35:22 GMT
4
+ */
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ function __accessProp(key) {
10
+ return this[key];
11
+ }
12
+ var __toCommonJS = (from) => {
13
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
14
+ if (entry)
15
+ return entry;
16
+ entry = __defProp({}, "__esModule", { value: true });
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (var key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(entry, key))
20
+ __defProp(entry, key, {
21
+ get: __accessProp.bind(from, key),
22
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
23
+ });
24
+ }
25
+ __moduleCache.set(from, entry);
26
+ return entry;
27
+ };
28
+ var __moduleCache;
29
+ var __returnValue = (v) => v;
30
+ function __exportSetter(name, newValue) {
31
+ this[name] = __returnValue.bind(null, newValue);
32
+ }
33
+ var __export = (target, all) => {
34
+ for (var name in all)
35
+ __defProp(target, name, {
36
+ get: all[name],
37
+ enumerable: true,
38
+ configurable: true,
39
+ set: __exportSetter.bind(all, name)
40
+ });
41
+ };
42
+ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
43
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
44
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
45
+ r = Reflect.decorate(decorators, target, key, desc);
46
+ else
47
+ for (var i = decorators.length - 1;i >= 0; i--)
48
+ if (d = decorators[i])
49
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
50
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
51
+ };
52
+
53
+ // src/index.ts
54
+ var exports_src = {};
55
+ __export(exports_src, {
56
+ WebRTCStreamer: () => WebRTCStreamer,
57
+ VERSION: () => VERSION,
58
+ StreamerError: () => StreamerError,
59
+ PermissionName: () => PermissionName,
60
+ MediaUtils: () => MediaUtils,
61
+ MediaErrorType: () => MediaErrorType
62
+ });
63
+ module.exports = __toCommonJS(exports_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
+
73
+ // src/constants.ts
74
+ var DEFAULT_STUN_SERVERS = [{ urls: ["stun:videostun.mycdn.me:19302"] }];
75
+ var DEFAULT_WS_SERVER = "wss://ovsu.mycdn.me/publish";
76
+ var WS_CLOSE_CODE = 1000;
77
+ var DEFAULT_FRAME_RATE = 15;
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 ||= {});
84
+ var MediaErrorType;
85
+ ((MediaErrorType2) => {
86
+ MediaErrorType2["UNKNOWN"] = "unknown";
87
+ MediaErrorType2["ACCESS"] = "access";
88
+ MediaErrorType2["PERMISSION"] = "permission";
89
+ MediaErrorType2["DEVICES_NOT_FOUND"] = "devices_not_found";
90
+ MediaErrorType2["DEVICES_NOT_SUPPORTED"] = "devices_not_supported";
91
+ })(MediaErrorType ||= {});
92
+ var StreamerError;
93
+ ((StreamerError2) => {
94
+ StreamerError2["SOCKET"] = "socket";
95
+ StreamerError2["CONNECTION"] = "connection";
96
+ StreamerError2["NO_STREAM_DATA"] = "no_stream_data";
97
+ StreamerError2["PEERCONNECTION"] = "peerconnection";
98
+ StreamerError2["CONSTRAINTS"] = "constraints";
99
+ })(StreamerError ||= {});
100
+
101
+ // src/MediaConstraints.ts
102
+ class MediaConstraints {
103
+ config;
104
+ audio;
105
+ video;
106
+ constructor(config) {
107
+ this.config = config;
108
+ this.audio = false;
109
+ this.video = false;
110
+ const { audio, video } = this.config;
111
+ if (audio) {
112
+ const deviceId = typeof audio === "boolean" ? null : audio.deviceId;
113
+ this.audio = deviceId ? { deviceId: { exact: deviceId } } : true;
114
+ }
115
+ if (video) {
116
+ const videoConfig = typeof video === "boolean" ? {} : video;
117
+ const { minWidth, maxWidth, minHeight, maxHeight, aspectRatio, deviceId, facingMode } = videoConfig;
118
+ this.video = {
119
+ width: { min: minWidth, max: maxWidth || 3840, ideal: 1920 },
120
+ height: { min: minHeight, max: maxHeight || 2160, ideal: 1080 },
121
+ aspectRatio: { ideal: aspectRatio || 16 / 9 }
122
+ };
123
+ if (facingMode) {
124
+ this.video.facingMode = { exact: facingMode };
125
+ } else if (deviceId) {
126
+ this.video.deviceId = { exact: deviceId };
127
+ }
128
+ }
129
+ }
130
+ getNative() {
131
+ return Object.assign({}, { audio: this.audio, video: this.video });
132
+ }
133
+ }
134
+
135
+ // src/utils.ts
136
+ var getWindow = () => {
137
+ return globalThis;
138
+ };
139
+ var getSafariVersion = (userAgent) => {
140
+ const ua = userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : "");
141
+ if (!ua) {
142
+ return;
143
+ }
144
+ const isSafari = /webkit/i.test(ua) && /safari/i.test(ua) && !/chrome|crios|chromium|yabrowser|samsungbrowser|opr\/|edg/i.test(ua);
145
+ if (!isSafari) {
146
+ return;
147
+ }
148
+ const versionMatch = ua.match(/Version\/(\d+)/);
149
+ if (!versionMatch) {
150
+ return;
151
+ }
152
+ const version = parseInt(versionMatch[1], 10);
153
+ return isNaN(version) ? undefined : version;
154
+ };
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
+ }
183
+ }
184
+ throw new Error("unknown");
185
+ });
186
+ };
187
+ var getDisplayMedia = (constraints) => getWindow().navigator.mediaDevices.getDisplayMedia(constraints.getNative()).catch((e) => {
188
+ if (e instanceof Error) {
189
+ switch (e.name) {
190
+ case "PermissionDeniedError":
191
+ case "SecurityError":
192
+ case "NotAllowedError":
193
+ throw new Error("permission");
194
+ default:
195
+ throw new Error("access");
196
+ }
197
+ }
198
+ throw new Error("unknown");
199
+ });
200
+ var omitKeys = (data, keys) => {
201
+ return Object.fromEntries(Object.entries(data).filter(([k]) => !keys.includes(k)));
202
+ };
203
+ var serializeTrack = (track) => {
204
+ return {
205
+ on: track.enabled,
206
+ k: track.kind,
207
+ ...track.contentHint && { h: track.contentHint }
208
+ };
209
+ };
210
+ var serializeStream = (stream) => {
211
+ return {
212
+ t: stream.getTracks().map(serializeTrack)
213
+ };
214
+ };
215
+ var serializeConfig = (cfg) => {
216
+ return {
217
+ key: cfg.streamKey,
218
+ ...cfg.audioOnly && { audioOnly: true },
219
+ ...cfg.lockOrientation && { lockOrientation: true },
220
+ ...cfg.mediaConfig && { mediaConfig: cfg.mediaConfig },
221
+ ...cfg.screenShare && { screenShare: omitKeys(cfg.screenShare, ["onEnded"]) }
222
+ };
223
+ };
224
+ var serializeMediaDevices = (devices) => {
225
+ return devices.map((d) => ({
226
+ id: d.deviceId.slice(0, 8),
227
+ kind: d.kind,
228
+ label: d.label
229
+ }));
230
+ };
231
+
232
+ // src/env.ts
233
+ var VERSION = "1.0.1-dev.2e8c6c4.0";
234
+ // src/WebRTCStreamer.ts
235
+ var import_videoplayer_shared = require("@vkontakte/videoplayer-shared");
236
+
237
+ // src/ScreenConstraints.ts
238
+ class ScreenConstraints extends MediaConstraints {
239
+ constructor({ width, height, frameRate = DEFAULT_FRAME_RATE }) {
240
+ super({
241
+ video: true,
242
+ audio: false
243
+ });
244
+ if (typeof this.video === "object") {
245
+ delete this.video.deviceId;
246
+ delete this.video.aspectRatio;
247
+ delete this.video.frameRate;
248
+ delete this.video.facingMode;
249
+ } else {
250
+ this.video = {};
251
+ }
252
+ this.video.cursor = "motion";
253
+ this.video.width = width;
254
+ this.video.height = height;
255
+ this.video.frameRate = frameRate;
256
+ if (getSafariVersion() === 16) {
257
+ this.video.width = { max: width };
258
+ this.video.height = { max: height };
259
+ }
260
+ }
261
+ }
262
+
263
+ // src/WebRTCStreamer.ts
264
+ class WebRTCStreamer {
265
+ config;
266
+ #messagesQueue = [];
267
+ #ws;
268
+ #peerConnection;
269
+ #stream;
270
+ #screenShareTrack = null;
271
+ #connected = false;
272
+ #destroying = false;
273
+ #cameraId;
274
+ #microphoneId;
275
+ #muted = false;
276
+ static notDestroying(_target, _propertyKey, descriptor) {
277
+ const original = descriptor.value;
278
+ descriptor.value = function(...args) {
279
+ if (this.#destroying) {
280
+ return;
281
+ }
282
+ return original.apply(this, args);
283
+ };
284
+ return descriptor;
285
+ }
286
+ constructor(config) {
287
+ this.config = config;
288
+ }
289
+ callback(name, ...args) {
290
+ const fn = this.config.callbacks[name];
291
+ if (fn && !this.#destroying) {
292
+ fn?.(...args);
293
+ }
294
+ }
295
+ get connected() {
296
+ return this.#connected;
297
+ }
298
+ async init() {
299
+ const { cameras, microphones } = await enumerateDevices();
300
+ this.tracerLog("init", {
301
+ cfg: serializeConfig(this.config),
302
+ d: serializeMediaDevices([...cameras, ...microphones])
303
+ });
304
+ let permissionName = "user_media" /* USER_MEDIA */;
305
+ const { audioOnly, mediaConfig, screenShare } = this.config;
306
+ try {
307
+ this.#stream = await getUserStream(mediaConfig ?? {
308
+ audio: true,
309
+ video: !screenShare && !audioOnly
310
+ });
311
+ if (!audioOnly && screenShare) {
312
+ permissionName = "display_media" /* DISPLAY_MEDIA */;
313
+ const screenShareTrack = await this.createScreenShareStream(screenShare);
314
+ if (screenShareTrack) {
315
+ const { frameRate = DEFAULT_FRAME_RATE } = screenShare;
316
+ try {
317
+ await screenShareTrack.applyConstraints({
318
+ frameRate: { exact: frameRate }
319
+ });
320
+ } catch (e) {
321
+ this.handleScreenShareConstraintsError(frameRate);
322
+ }
323
+ this.#stream.addTrack(screenShareTrack);
324
+ }
325
+ this.#screenShareTrack = screenShareTrack;
326
+ }
327
+ this.tracerLog("streamChanged", serializeStream(this.#stream));
328
+ this.callback("onStreamChanged", this.#stream);
329
+ } catch (err) {
330
+ if (err instanceof StreamerMediaError) {
331
+ this.tracerLog("permissionFailed", { name: permissionName, msg: err.message, code: err.name });
332
+ this.callback("onPermissionFailed", permissionName, err);
333
+ } else {
334
+ this.tracerLog("permissionFailed", { name: permissionName });
335
+ this.callback("onPermissionFailed", permissionName);
336
+ }
337
+ }
338
+ }
339
+ async connect() {
340
+ this.tracerLog("connect");
341
+ this.callback("onConnecting");
342
+ this.openSocket();
343
+ if (!this.#peerConnection) {
344
+ await this.createPeerConnection();
345
+ }
346
+ }
347
+ async switchCamera(deviceId) {
348
+ const { audioOnly } = this.config;
349
+ this.tracerLog("switchCamera", { id: deviceId, audioOnly });
350
+ if (audioOnly) {
351
+ return;
352
+ }
353
+ this.#cameraId = deviceId;
354
+ const newStream = await getUserStream({
355
+ audio: this.#microphoneId ? {
356
+ deviceId: this.#microphoneId
357
+ } : true,
358
+ video: {
359
+ deviceId: this.#cameraId
360
+ }
361
+ });
362
+ this.replaceStream(newStream);
363
+ if (this.#muted) {
364
+ this.setMicMuted(true);
365
+ }
366
+ }
367
+ async switchMicrophone(deviceId) {
368
+ this.tracerLog("switchMicrophone", { id: deviceId });
369
+ this.#microphoneId = deviceId;
370
+ const newStream = await getUserStream({
371
+ audio: {
372
+ deviceId: this.#microphoneId
373
+ },
374
+ video: this.#screenShareTrack ? false : this.#cameraId ? {
375
+ deviceId: this.#cameraId
376
+ } : true
377
+ });
378
+ if (this.#screenShareTrack) {
379
+ newStream.addTrack(this.#screenShareTrack);
380
+ }
381
+ this.replaceStream(newStream, true);
382
+ if (this.#muted) {
383
+ this.setMicMuted(true);
384
+ }
385
+ }
386
+ async enableScreenShare(config) {
387
+ this.tracerLog("enableScreenShare", omitKeys(config, ["onEnded"]));
388
+ const newStream = await getUserStream({
389
+ audio: this.#microphoneId ? { deviceId: this.#microphoneId } : true,
390
+ video: false
391
+ });
392
+ const screenShareTrack = await this.createScreenShareStream(config);
393
+ if (screenShareTrack) {
394
+ const { frameRate = DEFAULT_FRAME_RATE } = config;
395
+ try {
396
+ await screenShareTrack.applyConstraints({
397
+ frameRate: { exact: frameRate }
398
+ });
399
+ } catch (e) {
400
+ this.handleScreenShareConstraintsError(frameRate);
401
+ }
402
+ newStream.addTrack(screenShareTrack);
403
+ }
404
+ this.#screenShareTrack = screenShareTrack;
405
+ this.replaceStream(newStream);
406
+ if (this.#muted) {
407
+ this.setMicMuted(true);
408
+ }
409
+ }
410
+ async disableScreenShare(cameraDeviceId) {
411
+ this.tracerLog("disableScreenShare", cameraDeviceId ? { cid: cameraDeviceId } : undefined);
412
+ if (cameraDeviceId) {
413
+ await this.switchCamera(cameraDeviceId);
414
+ } else {
415
+ const { cameras } = await enumerateDevices();
416
+ const defaultCamera = cameras[0];
417
+ if (defaultCamera) {
418
+ await this.switchCamera(defaultCamera.deviceId);
419
+ }
420
+ }
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
+ }
475
+ setMicMuted(muted) {
476
+ this.tracerLog("setMicMuted", { m: muted });
477
+ this.#muted = muted;
478
+ this.#stream?.getAudioTracks().forEach((track) => {
479
+ track.enabled = !muted;
480
+ });
481
+ }
482
+ setCameraEnabled(enabled) {
483
+ this.tracerLog("setCameraEnabled", { on: enabled });
484
+ this.#stream?.getVideoTracks().forEach((track) => {
485
+ track.enabled = enabled;
486
+ });
487
+ }
488
+ destroy() {
489
+ this.#destroying = true;
490
+ this.tracerLog("destroy");
491
+ this.disconnect();
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;
499
+ }
500
+ }
501
+ disconnect() {
502
+ this.tracerLog("disconnect");
503
+ this.closePeerConnection();
504
+ if (this.socketOpened) {
505
+ this.send({ type: "BYE" });
506
+ this.closeWSConnection();
507
+ }
508
+ }
509
+ replaceStream(stream, keepScreenShare = false) {
510
+ this.#stream?.getTracks().forEach((track) => {
511
+ const isScreenShare = track.contentHint === SCREEN_SHARE_CONTENT_TEXTHINT;
512
+ if (!isScreenShare || !keepScreenShare) {
513
+ track.stop();
514
+ if (isScreenShare) {
515
+ this.#screenShareTrack = null;
516
+ }
517
+ }
518
+ this.#stream?.removeTrack(track);
519
+ });
520
+ this.#stream = stream;
521
+ this.tracerLog("streamChanged", serializeStream(stream));
522
+ this.callback("onStreamChanged", this.#stream);
523
+ this.replaceTracksInPeerConnection(this.#stream);
524
+ }
525
+ replaceTracksInPeerConnection(stream, keepScreenShare = false) {
526
+ if (!this.#peerConnection) {
527
+ return;
528
+ }
529
+ this.#peerConnection.getTransceivers().forEach(({ sender }) => {
530
+ const { track } = sender;
531
+ if (track && (track.contentHint !== SCREEN_SHARE_CONTENT_TEXTHINT || !keepScreenShare)) {
532
+ track.stop();
533
+ }
534
+ stream.getTracks().forEach((newTrack) => {
535
+ if (track?.kind === newTrack.kind) {
536
+ sender.replaceTrack(newTrack).then(() => {}, () => {});
537
+ }
538
+ });
539
+ });
540
+ }
541
+ get socketOpened() {
542
+ return this.#ws?.readyState === WebSocket.OPEN;
543
+ }
544
+ async createScreenShareStream(screenShare) {
545
+ const { width, height, onEnded = null } = screenShare;
546
+ const displayStream = await getDisplayMedia(new ScreenConstraints({ width, height }));
547
+ const screenShareTrack = displayStream ? displayStream.getVideoTracks()[0] : null;
548
+ if (screenShareTrack) {
549
+ screenShareTrack.contentHint = SCREEN_SHARE_CONTENT_TEXTHINT;
550
+ screenShareTrack.onended = () => {
551
+ this.#screenShareTrack = null;
552
+ onEnded?.();
553
+ };
554
+ }
555
+ return screenShareTrack;
556
+ }
557
+ openSocket() {
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;
563
+ }
564
+ }
565
+ handleWSOpen = () => {
566
+ this.sendMessageFromQueue();
567
+ };
568
+ handleWSMessage = (event) => {
569
+ if (this.#destroying || !this.#ws || this.#ws.readyState >= WebSocket.CLOSING) {
570
+ return;
571
+ }
572
+ const message = this.parseMessage(event.data);
573
+ switch (message.type) {
574
+ case "INVITE":
575
+ this.handleInviteMessage(message);
576
+ break;
577
+ case "ERROR":
578
+ this.handleError("socket" /* SOCKET */, message);
579
+ break;
580
+ case "STATUS":
581
+ this.handleStatusMessage(message);
582
+ break;
583
+ }
584
+ };
585
+ handleWSClose = (event) => {
586
+ this.closePeerConnection();
587
+ if (!this.#ws) {
588
+ return;
589
+ }
590
+ this.#messagesQueue = [];
591
+ this.#connected = false;
592
+ this.#ws = undefined;
593
+ this.tracerLog("disconnected", { code: event.code });
594
+ this.callback("onDisconnected", event);
595
+ };
596
+ send(message) {
597
+ this.#messagesQueue.push(message);
598
+ if (this.socketOpened) {
599
+ this.sendMessageFromQueue();
600
+ }
601
+ }
602
+ sendMessageFromQueue() {
603
+ while (this.#messagesQueue.length > 0) {
604
+ if (this.socketOpened) {
605
+ const message = this.#messagesQueue.shift();
606
+ this.#ws?.send(JSON.stringify(message));
607
+ }
608
+ }
609
+ }
610
+ handleStatusMessage(msg) {
611
+ const { status, message } = msg;
612
+ if (status === "INFO" && message === "no_stream_data") {
613
+ this.handleError("no_stream_data" /* NO_STREAM_DATA */, msg);
614
+ }
615
+ }
616
+ handleInviteMessage(message) {
617
+ switch (message.inviteType) {
618
+ case "ANSWER":
619
+ this.handleAnswer(message.sdp);
620
+ break;
621
+ case "CANDIDATE":
622
+ if (message.candidate) {
623
+ this.tracerLog("gotRTCCandidate", { v: message.candidate });
624
+ this.handleCandidate(message.candidate);
625
+ }
626
+ break;
627
+ default:
628
+ break;
629
+ }
630
+ }
631
+ handleAnswer(sdp) {
632
+ this.#peerConnection?.setRemoteDescription(new RTCSessionDescription({ type: "answer", sdp }));
633
+ }
634
+ handleCandidate(candidate) {
635
+ this.#peerConnection?.addIceCandidate(new RTCIceCandidate(candidate));
636
+ }
637
+ handleScreenShareConstraintsError(frameRate) {
638
+ this.tracerLog("error", { type: "constraints" /* CONSTRAINTS */, frameRate });
639
+ this.callback("onError", "constraints" /* CONSTRAINTS */);
640
+ }
641
+ handleError(err, message) {
642
+ if (["no_stream_data" /* NO_STREAM_DATA */, "peerconnection" /* PEERCONNECTION */].includes(err)) {
643
+ this.closePeerConnection();
644
+ this.closeWSConnection();
645
+ }
646
+ const reason = message ? typeof message === "string" ? message : message.text ?? message.message : undefined;
647
+ this.tracerLog("error", { type: err, ...reason && { r: reason } });
648
+ this.callback("onError", err, reason);
649
+ }
650
+ async createPeerConnection() {
651
+ try {
652
+ this.#peerConnection = new RTCPeerConnection({
653
+ iceServers: this.config.stunServers ?? DEFAULT_STUN_SERVERS,
654
+ rtcpMuxPolicy: "require",
655
+ bundlePolicy: "max-compat"
656
+ });
657
+ this.#peerConnection.onicecandidate = this.handleRTCIceCandidate;
658
+ this.#peerConnection.onsignalingstatechange = this.handleRTCSignalingStateChange;
659
+ this.#peerConnection.oniceconnectionstatechange = this.handleRTCIceConnectionStateChange;
660
+ this.#stream?.getTracks().forEach((track) => {
661
+ if (track.kind === "video") {
662
+ track.contentHint = "text";
663
+ }
664
+ this.#stream && this.#peerConnection?.addTrack(track, this.#stream);
665
+ });
666
+ } catch (e) {
667
+ this.handleError("peerconnection" /* PEERCONNECTION */, "create peer connection failed");
668
+ return;
669
+ }
670
+ try {
671
+ const offer = await this.#peerConnection.createOffer();
672
+ if (this.config.lockOrientation) {
673
+ offer.sdp = offer.sdp?.replace(/a=extmap:[0-9]+ urn:3gpp:video-orientation[\r\n]+/g, "");
674
+ }
675
+ await this.setDescription(offer);
676
+ } catch (e) {
677
+ this.handleError("peerconnection" /* PEERCONNECTION */, "set offer description failed");
678
+ }
679
+ }
680
+ handleRTCIceCandidate = ({ candidate }) => {
681
+ if (candidate) {
682
+ this.tracerLog("sendRTCCandidate", { v: candidate.candidate });
683
+ this.send({
684
+ type: "INVITE",
685
+ promoCall: false,
686
+ inviteType: "CANDIDATE",
687
+ candidate
688
+ });
689
+ } else {
690
+ this.send({ type: "INVITE", promoCall: false, inviteType: "CANDIDATE" });
691
+ }
692
+ };
693
+ handleRTCSignalingStateChange = () => {
694
+ if (!this.#peerConnection) {
695
+ return;
696
+ }
697
+ switch (this.#peerConnection.signalingState) {
698
+ case "have-local-offer":
699
+ const sdp = this.#peerConnection.localDescription?.sdp;
700
+ this.send({
701
+ type: "INVITE",
702
+ inviteType: "OFFER",
703
+ promoCall: false,
704
+ streamKey: this.config.streamKey,
705
+ sdp
706
+ });
707
+ break;
708
+ case "closed":
709
+ this.handleError("peerconnection" /* PEERCONNECTION */, "signalling closed");
710
+ break;
711
+ }
712
+ };
713
+ handleRTCIceConnectionStateChange = () => {
714
+ if (!this.#peerConnection) {
715
+ return;
716
+ }
717
+ switch (this.#peerConnection.iceConnectionState) {
718
+ case "failed":
719
+ this.handleError("peerconnection" /* PEERCONNECTION */, "ice connection failed");
720
+ break;
721
+ case "disconnected":
722
+ this.disconnect();
723
+ break;
724
+ case "connected":
725
+ this.#connected = true;
726
+ this.tracerLog("connected");
727
+ this.callback("onConnected");
728
+ break;
729
+ }
730
+ };
731
+ async setDescription(description) {
732
+ try {
733
+ await this.#peerConnection?.setLocalDescription(description);
734
+ } catch (e) {
735
+ this.handleError("peerconnection" /* PEERCONNECTION */, "set local description failed");
736
+ }
737
+ }
738
+ closePeerConnection() {
739
+ if (this.#peerConnection) {
740
+ if (this.#peerConnection.signalingState !== "closed") {
741
+ this.#peerConnection.close();
742
+ }
743
+ this.#peerConnection = undefined;
744
+ }
745
+ }
746
+ closeWSConnection() {
747
+ if (this.#ws && this.#ws.readyState < WebSocket.CLOSING) {
748
+ this.#ws.close(WS_CLOSE_CODE);
749
+ }
750
+ }
751
+ parseMessage(data) {
752
+ try {
753
+ return JSON.parse(data);
754
+ } catch (e) {
755
+ return { type: "EMPTY" };
756
+ }
757
+ }
758
+ tracerLog(event, data) {
759
+ return this.config.tracer?.log(event, import_videoplayer_shared.flattenObject(data));
760
+ }
761
+ logStat(event, data) {
762
+ this.config.statisticsLogger?.log(event, data);
763
+ }
764
+ }
765
+ __legacyDecorateClassTS([
766
+ WebRTCStreamer.notDestroying
767
+ ], WebRTCStreamer.prototype, "init", null);
768
+ __legacyDecorateClassTS([
769
+ WebRTCStreamer.notDestroying
770
+ ], WebRTCStreamer.prototype, "connect", null);
771
+ __legacyDecorateClassTS([
772
+ WebRTCStreamer.notDestroying
773
+ ], WebRTCStreamer.prototype, "switchCamera", null);
774
+ __legacyDecorateClassTS([
775
+ WebRTCStreamer.notDestroying
776
+ ], WebRTCStreamer.prototype, "switchMicrophone", null);
777
+ __legacyDecorateClassTS([
778
+ WebRTCStreamer.notDestroying
779
+ ], WebRTCStreamer.prototype, "enableScreenShare", null);
780
+ __legacyDecorateClassTS([
781
+ WebRTCStreamer.notDestroying
782
+ ], WebRTCStreamer.prototype, "disableScreenShare", null);
783
+ __legacyDecorateClassTS([
784
+ WebRTCStreamer.notDestroying
785
+ ], WebRTCStreamer.prototype, "switchMediaDevices", null);
786
+ __legacyDecorateClassTS([
787
+ WebRTCStreamer.notDestroying
788
+ ], WebRTCStreamer.prototype, "setMicMuted", null);
789
+ __legacyDecorateClassTS([
790
+ WebRTCStreamer.notDestroying
791
+ ], WebRTCStreamer.prototype, "setCameraEnabled", null);
792
+ __legacyDecorateClassTS([
793
+ WebRTCStreamer.notDestroying
794
+ ], WebRTCStreamer.prototype, "destroy", null);
795
+
796
+ // src/index.ts
797
+ var MediaUtils = { enumerateDevices, getUserStream };
798
+
799
+ //# debugId=5A8DEEFE88A024DF64756E2164756E21
800
+
801
+ //# sourceMappingURL=media-streaming.cjs.map