@eyepop.ai/eyepop 0.10.0 → 0.11.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/README.md +49 -8
- package/dist/eyepop.min.js +1 -1
- package/dist/eyepop.min.js.LICENSE.txt +18 -0
- package/dist/index.d.mts +19 -6
- package/dist/index.d.ts +19 -6
- package/dist/index.js +488 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +478 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __commonJS = (cb, mod) => function __require() {
|
|
7
9
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
@@ -18,6 +20,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
20
|
}
|
|
19
21
|
return to;
|
|
20
22
|
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
21
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
32
|
|
|
23
33
|
// node_modules/mime-db/db.json
|
|
@@ -9054,6 +9064,39 @@ var LoadFromJob = class extends AbstractJob {
|
|
|
9054
9064
|
return response;
|
|
9055
9065
|
}
|
|
9056
9066
|
};
|
|
9067
|
+
var LoadLiveIngressJob = class extends AbstractJob {
|
|
9068
|
+
constructor(ingressId, getSession, client, requestLogger) {
|
|
9069
|
+
super(getSession, client, requestLogger);
|
|
9070
|
+
this._ingressId = ingressId;
|
|
9071
|
+
}
|
|
9072
|
+
get [Symbol.toStringTag]() {
|
|
9073
|
+
return "loadLiveIngressJob";
|
|
9074
|
+
}
|
|
9075
|
+
async startJob() {
|
|
9076
|
+
const body = {
|
|
9077
|
+
"sourceType": "LIVE_INGRESS",
|
|
9078
|
+
"liveIngressId": this._ingressId
|
|
9079
|
+
};
|
|
9080
|
+
const session = await this._getSession();
|
|
9081
|
+
const headers = {
|
|
9082
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9083
|
+
"Accept": "application/jsonl",
|
|
9084
|
+
"Content-Type": "application/json"
|
|
9085
|
+
};
|
|
9086
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9087
|
+
this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._ingressId);
|
|
9088
|
+
const response = await this._client.fetch(patchUrl, {
|
|
9089
|
+
headers,
|
|
9090
|
+
method: "PATCH",
|
|
9091
|
+
body: JSON.stringify(body),
|
|
9092
|
+
signal: this._controller.signal,
|
|
9093
|
+
// @ts-ignore
|
|
9094
|
+
dispatcher: this._dispatcher
|
|
9095
|
+
});
|
|
9096
|
+
this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._ingressId);
|
|
9097
|
+
return response;
|
|
9098
|
+
}
|
|
9099
|
+
};
|
|
9057
9100
|
|
|
9058
9101
|
// src/shims/http_client.ts
|
|
9059
9102
|
var createHttpClient;
|
|
@@ -9222,6 +9265,374 @@ var Semaphore = class {
|
|
|
9222
9265
|
}
|
|
9223
9266
|
};
|
|
9224
9267
|
|
|
9268
|
+
// node_modules/uuid/dist/esm-node/rng.js
|
|
9269
|
+
var import_crypto = __toESM(require("crypto"));
|
|
9270
|
+
var rnds8Pool = new Uint8Array(256);
|
|
9271
|
+
var poolPtr = rnds8Pool.length;
|
|
9272
|
+
function rng() {
|
|
9273
|
+
if (poolPtr > rnds8Pool.length - 16) {
|
|
9274
|
+
import_crypto.default.randomFillSync(rnds8Pool);
|
|
9275
|
+
poolPtr = 0;
|
|
9276
|
+
}
|
|
9277
|
+
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
9278
|
+
}
|
|
9279
|
+
|
|
9280
|
+
// node_modules/uuid/dist/esm-node/stringify.js
|
|
9281
|
+
var byteToHex = [];
|
|
9282
|
+
for (let i = 0; i < 256; ++i) {
|
|
9283
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
9284
|
+
}
|
|
9285
|
+
function unsafeStringify(arr, offset = 0) {
|
|
9286
|
+
return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
|
|
9287
|
+
}
|
|
9288
|
+
|
|
9289
|
+
// node_modules/uuid/dist/esm-node/native.js
|
|
9290
|
+
var import_crypto2 = __toESM(require("crypto"));
|
|
9291
|
+
var native_default = {
|
|
9292
|
+
randomUUID: import_crypto2.default.randomUUID
|
|
9293
|
+
};
|
|
9294
|
+
|
|
9295
|
+
// node_modules/uuid/dist/esm-node/v4.js
|
|
9296
|
+
function v4(options, buf, offset) {
|
|
9297
|
+
if (native_default.randomUUID && !buf && !options) {
|
|
9298
|
+
return native_default.randomUUID();
|
|
9299
|
+
}
|
|
9300
|
+
options = options || {};
|
|
9301
|
+
const rnds = options.random || (options.rng || rng)();
|
|
9302
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
9303
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
9304
|
+
if (buf) {
|
|
9305
|
+
offset = offset || 0;
|
|
9306
|
+
for (let i = 0; i < 16; ++i) {
|
|
9307
|
+
buf[offset + i] = rnds[i];
|
|
9308
|
+
}
|
|
9309
|
+
return buf;
|
|
9310
|
+
}
|
|
9311
|
+
return unsafeStringify(rnds);
|
|
9312
|
+
}
|
|
9313
|
+
var v4_default = v4;
|
|
9314
|
+
|
|
9315
|
+
// src/web_rtc_base.ts
|
|
9316
|
+
var WebRtcBase = class {
|
|
9317
|
+
constructor(getSession, client, requestLogger) {
|
|
9318
|
+
this._pc = null;
|
|
9319
|
+
this._getSession = getSession;
|
|
9320
|
+
this._client = client;
|
|
9321
|
+
this._requestLogger = requestLogger;
|
|
9322
|
+
this._eTag = "";
|
|
9323
|
+
this._queuedCandidates = [];
|
|
9324
|
+
this._offerData = null;
|
|
9325
|
+
}
|
|
9326
|
+
static linkToIceServers(links) {
|
|
9327
|
+
const servers = links !== null ? links.split(", ").map((link) => {
|
|
9328
|
+
const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
9329
|
+
if (!m) {
|
|
9330
|
+
return null;
|
|
9331
|
+
}
|
|
9332
|
+
const iceServer = {
|
|
9333
|
+
urls: [m[1]],
|
|
9334
|
+
username: Whip.unquoteCredential(m[3]),
|
|
9335
|
+
credential: Whip.unquoteCredential(m[4])
|
|
9336
|
+
// credentialType: m[3]? "password" : undefined
|
|
9337
|
+
};
|
|
9338
|
+
return iceServer;
|
|
9339
|
+
}) : [];
|
|
9340
|
+
return servers.filter(function(el) {
|
|
9341
|
+
return el != null;
|
|
9342
|
+
});
|
|
9343
|
+
}
|
|
9344
|
+
static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
|
|
9345
|
+
const sections = answer.split("m=");
|
|
9346
|
+
for (let i = 0; i < sections.length; i++) {
|
|
9347
|
+
const section = sections[i];
|
|
9348
|
+
if (section.startsWith("video")) {
|
|
9349
|
+
sections[i] = Whip.setVideoBitrate(Whip.setCodec(section, videoCodec), videoBitrate);
|
|
9350
|
+
} else if (section.startsWith("audio")) {
|
|
9351
|
+
sections[i] = Whip.setAudioBitrate(Whip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9352
|
+
}
|
|
9353
|
+
}
|
|
9354
|
+
return sections.join("m=");
|
|
9355
|
+
}
|
|
9356
|
+
static setCodec(section, codec) {
|
|
9357
|
+
const lines = section.split("\r\n");
|
|
9358
|
+
const lines2 = [];
|
|
9359
|
+
const payloadFormats = [];
|
|
9360
|
+
for (const line of lines) {
|
|
9361
|
+
if (!line.startsWith("a=rtpmap:")) {
|
|
9362
|
+
lines2.push(line);
|
|
9363
|
+
} else {
|
|
9364
|
+
if (codec && line.toLowerCase().includes(codec)) {
|
|
9365
|
+
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9366
|
+
lines2.push(line);
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
9369
|
+
}
|
|
9370
|
+
const lines3 = [];
|
|
9371
|
+
for (const line of lines2) {
|
|
9372
|
+
if (line.startsWith("a=fmtp:")) {
|
|
9373
|
+
if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
|
|
9374
|
+
lines3.push(line);
|
|
9375
|
+
}
|
|
9376
|
+
} else if (line.startsWith("a=rtcp-fb:")) {
|
|
9377
|
+
if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
|
|
9378
|
+
lines3.push(line);
|
|
9379
|
+
}
|
|
9380
|
+
} else {
|
|
9381
|
+
lines3.push(line);
|
|
9382
|
+
}
|
|
9383
|
+
}
|
|
9384
|
+
return lines3.join("\r\n");
|
|
9385
|
+
}
|
|
9386
|
+
static setVideoBitrate(section, bitrate) {
|
|
9387
|
+
let lines = section.split("\r\n");
|
|
9388
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9389
|
+
if (lines[i].startsWith("c=")) {
|
|
9390
|
+
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9391
|
+
break;
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
return lines.join("\r\n");
|
|
9395
|
+
}
|
|
9396
|
+
static setAudioBitrate(section, bitrate, voice) {
|
|
9397
|
+
let opusPayloadFormat = "";
|
|
9398
|
+
let lines = section.split("\r\n");
|
|
9399
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9400
|
+
if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
|
|
9401
|
+
opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
|
|
9402
|
+
break;
|
|
9403
|
+
}
|
|
9404
|
+
}
|
|
9405
|
+
if (opusPayloadFormat === "") {
|
|
9406
|
+
return section;
|
|
9407
|
+
}
|
|
9408
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9409
|
+
if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
|
|
9410
|
+
if (voice) {
|
|
9411
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
|
|
9412
|
+
} else {
|
|
9413
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
|
|
9414
|
+
}
|
|
9415
|
+
}
|
|
9416
|
+
}
|
|
9417
|
+
return lines.join("\r\n");
|
|
9418
|
+
}
|
|
9419
|
+
static parseOffer(offer) {
|
|
9420
|
+
let medias = [];
|
|
9421
|
+
let iceUfrag = "";
|
|
9422
|
+
let icePwd = "";
|
|
9423
|
+
for (const line of offer.split("\r\n")) {
|
|
9424
|
+
if (line.startsWith("m=")) {
|
|
9425
|
+
medias.push(line.slice("m=".length));
|
|
9426
|
+
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9427
|
+
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9428
|
+
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9429
|
+
icePwd = line.slice("a=ice-pwd:".length);
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
return {
|
|
9433
|
+
iceUfrag,
|
|
9434
|
+
icePwd,
|
|
9435
|
+
medias
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9438
|
+
static generateSdpFragment(offerData, candidates) {
|
|
9439
|
+
const candidatesByMedia = /* @__PURE__ */ new Map();
|
|
9440
|
+
for (const candidate of candidates) {
|
|
9441
|
+
if (candidate.sdpMLineIndex !== null) {
|
|
9442
|
+
const mid2 = candidate.sdpMLineIndex;
|
|
9443
|
+
let matched = candidatesByMedia.get(mid2);
|
|
9444
|
+
if (matched === void 0) {
|
|
9445
|
+
matched = [];
|
|
9446
|
+
candidatesByMedia.set(mid2, matched);
|
|
9447
|
+
}
|
|
9448
|
+
matched.push(candidate);
|
|
9449
|
+
}
|
|
9450
|
+
}
|
|
9451
|
+
let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
|
|
9452
|
+
let mid = 0;
|
|
9453
|
+
for (const media of offerData.medias) {
|
|
9454
|
+
let matched = candidatesByMedia.get(mid);
|
|
9455
|
+
if (matched !== void 0) {
|
|
9456
|
+
frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
|
|
9457
|
+
for (const candidate of matched) {
|
|
9458
|
+
frag += "a=" + candidate.candidate + "\r\n";
|
|
9459
|
+
}
|
|
9460
|
+
}
|
|
9461
|
+
mid++;
|
|
9462
|
+
}
|
|
9463
|
+
return frag;
|
|
9464
|
+
}
|
|
9465
|
+
static unquoteCredential(v) {
|
|
9466
|
+
if (!v) {
|
|
9467
|
+
return "";
|
|
9468
|
+
}
|
|
9469
|
+
return JSON.parse(`"${v}"`);
|
|
9470
|
+
}
|
|
9471
|
+
};
|
|
9472
|
+
|
|
9473
|
+
// src/whip.ts
|
|
9474
|
+
var Whip = class _Whip extends WebRtcBase {
|
|
9475
|
+
constructor(stream, getSession, client, requestLogger) {
|
|
9476
|
+
super(getSession, client, requestLogger);
|
|
9477
|
+
this._ingressId = v4_default().toString();
|
|
9478
|
+
this._stream = stream;
|
|
9479
|
+
}
|
|
9480
|
+
ingressId() {
|
|
9481
|
+
if (!this._ingressId) {
|
|
9482
|
+
throw new Error("not initialized");
|
|
9483
|
+
}
|
|
9484
|
+
return this._ingressId;
|
|
9485
|
+
}
|
|
9486
|
+
async start() {
|
|
9487
|
+
const session = await this._getSession();
|
|
9488
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9489
|
+
this._requestLogger.debug("before GET: %s", ingressUrl);
|
|
9490
|
+
const headers = {
|
|
9491
|
+
"Authorization": `Bearer ${session.accessToken}`
|
|
9492
|
+
};
|
|
9493
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9494
|
+
headers,
|
|
9495
|
+
method: "GET"
|
|
9496
|
+
});
|
|
9497
|
+
if (response.status >= 300) {
|
|
9498
|
+
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9499
|
+
}
|
|
9500
|
+
return this.onIceServers(response);
|
|
9501
|
+
}
|
|
9502
|
+
async onIceServers(response) {
|
|
9503
|
+
if (!this._stream) {
|
|
9504
|
+
throw new Error("onIceServers no stream");
|
|
9505
|
+
}
|
|
9506
|
+
const stream = this._stream;
|
|
9507
|
+
const pc = new RTCPeerConnection({
|
|
9508
|
+
iceServers: _Whip.linkToIceServers(response.headers.get("Link"))
|
|
9509
|
+
});
|
|
9510
|
+
this._pc = pc;
|
|
9511
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9512
|
+
return new Promise(async (resolve2, reject) => {
|
|
9513
|
+
pc.oniceconnectionstatechange = () => {
|
|
9514
|
+
switch (pc.iceConnectionState) {
|
|
9515
|
+
case "failed":
|
|
9516
|
+
case "disconnected":
|
|
9517
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9518
|
+
break;
|
|
9519
|
+
case "connected":
|
|
9520
|
+
resolve2(this);
|
|
9521
|
+
break;
|
|
9522
|
+
}
|
|
9523
|
+
};
|
|
9524
|
+
stream.getTracks().forEach((track) => {
|
|
9525
|
+
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9526
|
+
pc.addTrack(track, stream);
|
|
9527
|
+
});
|
|
9528
|
+
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9529
|
+
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9530
|
+
pc.addTrack(trackEvent.track, stream);
|
|
9531
|
+
});
|
|
9532
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
9533
|
+
});
|
|
9534
|
+
}
|
|
9535
|
+
async onLocalCandidate(evt) {
|
|
9536
|
+
if (evt.candidate !== null) {
|
|
9537
|
+
if (this._eTag === "") {
|
|
9538
|
+
this._queuedCandidates.push(evt.candidate);
|
|
9539
|
+
} else {
|
|
9540
|
+
await this.sendLocalCandidates([evt.candidate]);
|
|
9541
|
+
}
|
|
9542
|
+
}
|
|
9543
|
+
return this;
|
|
9544
|
+
}
|
|
9545
|
+
async onLocalOffer(offer) {
|
|
9546
|
+
if (!this._pc) {
|
|
9547
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9548
|
+
}
|
|
9549
|
+
if (!offer.sdp) {
|
|
9550
|
+
throw new Error("onLocalOffer no sdp");
|
|
9551
|
+
}
|
|
9552
|
+
this._offerData = _Whip.parseOffer(offer.sdp);
|
|
9553
|
+
await this._pc.setLocalDescription(offer);
|
|
9554
|
+
const session = await this._getSession();
|
|
9555
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9556
|
+
this._requestLogger.debug("before GET: %s", ingressUrl);
|
|
9557
|
+
const headers = {
|
|
9558
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9559
|
+
"Content-Type": "application/sdp"
|
|
9560
|
+
};
|
|
9561
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9562
|
+
headers,
|
|
9563
|
+
method: "POST",
|
|
9564
|
+
body: offer.sdp
|
|
9565
|
+
});
|
|
9566
|
+
if (response.status != 201) {
|
|
9567
|
+
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9568
|
+
}
|
|
9569
|
+
this._eTag = response.headers.get("ETag") ?? "";
|
|
9570
|
+
return this.onRemoteAnswer(new RTCSessionDescription({
|
|
9571
|
+
type: "answer",
|
|
9572
|
+
sdp: await response.text()
|
|
9573
|
+
}));
|
|
9574
|
+
}
|
|
9575
|
+
async onRemoteAnswer(answer) {
|
|
9576
|
+
if (!this._pc) {
|
|
9577
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9578
|
+
}
|
|
9579
|
+
answer = new RTCSessionDescription({
|
|
9580
|
+
type: "answer",
|
|
9581
|
+
sdp: _Whip.editAnswer(
|
|
9582
|
+
answer.sdp,
|
|
9583
|
+
"h264/90000",
|
|
9584
|
+
void 0,
|
|
9585
|
+
5e3,
|
|
9586
|
+
void 0,
|
|
9587
|
+
true
|
|
9588
|
+
)
|
|
9589
|
+
});
|
|
9590
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
9591
|
+
if (this._queuedCandidates.length !== 0) {
|
|
9592
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9593
|
+
this._queuedCandidates = [];
|
|
9594
|
+
}
|
|
9595
|
+
return this;
|
|
9596
|
+
}
|
|
9597
|
+
async sendLocalCandidates(candidates) {
|
|
9598
|
+
if (!this._offerData) {
|
|
9599
|
+
throw new Error("sendLocalCandidates no offerData");
|
|
9600
|
+
}
|
|
9601
|
+
const session = await this._getSession();
|
|
9602
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9603
|
+
this._requestLogger.debug("before PATCH: %s", ingressUrl);
|
|
9604
|
+
const headers = {
|
|
9605
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9606
|
+
"Content-Type": "application/trickle-ice-sdpfrag",
|
|
9607
|
+
"If-Match": this._eTag
|
|
9608
|
+
};
|
|
9609
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9610
|
+
headers,
|
|
9611
|
+
method: "PATCH",
|
|
9612
|
+
body: _Whip.generateSdpFragment(this._offerData, candidates)
|
|
9613
|
+
});
|
|
9614
|
+
if (response.status != 204) {
|
|
9615
|
+
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9616
|
+
}
|
|
9617
|
+
return this;
|
|
9618
|
+
}
|
|
9619
|
+
async close() {
|
|
9620
|
+
const pc = this._pc;
|
|
9621
|
+
const stream = this._stream;
|
|
9622
|
+
this._stream = null;
|
|
9623
|
+
this._pc = null;
|
|
9624
|
+
if (stream) {
|
|
9625
|
+
const tracks = stream.getTracks();
|
|
9626
|
+
tracks.forEach((track) => {
|
|
9627
|
+
track.stop();
|
|
9628
|
+
});
|
|
9629
|
+
}
|
|
9630
|
+
if (pc) {
|
|
9631
|
+
return pc.close();
|
|
9632
|
+
}
|
|
9633
|
+
}
|
|
9634
|
+
};
|
|
9635
|
+
|
|
9225
9636
|
// src/shims/local_file.ts
|
|
9226
9637
|
var resolve;
|
|
9227
9638
|
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
@@ -9277,6 +9688,8 @@ var Endpoint = class {
|
|
|
9277
9688
|
this._client = null;
|
|
9278
9689
|
this._state = "Idle" /* Idle */;
|
|
9279
9690
|
this._stateChangeHandler = null;
|
|
9691
|
+
this._ingressEventHandler = null;
|
|
9692
|
+
this._ingressEventWs = null;
|
|
9280
9693
|
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
9281
9694
|
let rootLogger;
|
|
9282
9695
|
if (options.logger) {
|
|
@@ -9291,6 +9704,51 @@ var Endpoint = class {
|
|
|
9291
9704
|
this._stateChangeHandler = handler;
|
|
9292
9705
|
return this;
|
|
9293
9706
|
}
|
|
9707
|
+
async startIngressWs() {
|
|
9708
|
+
if (this._ingressEventWs || !this._baseUrl || !this._client) {
|
|
9709
|
+
return;
|
|
9710
|
+
}
|
|
9711
|
+
try {
|
|
9712
|
+
const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
|
|
9713
|
+
const headers = {
|
|
9714
|
+
"Authorization": await this.authorizationHeader()
|
|
9715
|
+
};
|
|
9716
|
+
this._requestLogger.debug("before GET %s", getTokenUrl);
|
|
9717
|
+
let response = await this._client.fetch(getTokenUrl, { headers });
|
|
9718
|
+
if (response.status == 401) {
|
|
9719
|
+
this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
|
|
9720
|
+
this._token = null;
|
|
9721
|
+
const headers2 = {
|
|
9722
|
+
"Authorization": await this.authorizationHeader()
|
|
9723
|
+
};
|
|
9724
|
+
this.updateState("FetchConfig" /* FetchConfig */);
|
|
9725
|
+
response = await this._client.fetch(getTokenUrl, { headers: headers2 });
|
|
9726
|
+
}
|
|
9727
|
+
if (response.status != 200) {
|
|
9728
|
+
const message = await response.text();
|
|
9729
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9730
|
+
}
|
|
9731
|
+
const wsAuthToken = await response.json();
|
|
9732
|
+
const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
|
|
9733
|
+
this._ingressEventWs = new WebSocket(wsUrl);
|
|
9734
|
+
this._ingressEventWs.addEventListener("message", (event) => {
|
|
9735
|
+
const ingressEvent = JSON.parse(event.data);
|
|
9736
|
+
if (this._ingressEventHandler) {
|
|
9737
|
+
this._ingressEventHandler(ingressEvent);
|
|
9738
|
+
}
|
|
9739
|
+
});
|
|
9740
|
+
} finally {
|
|
9741
|
+
this.updateState();
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
onIngressEvent(handler) {
|
|
9745
|
+
this._ingressEventHandler = handler;
|
|
9746
|
+
this.startIngressWs().then(() => {
|
|
9747
|
+
}).catch((reason) => {
|
|
9748
|
+
this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
|
|
9749
|
+
});
|
|
9750
|
+
return this;
|
|
9751
|
+
}
|
|
9294
9752
|
state() {
|
|
9295
9753
|
return this._state;
|
|
9296
9754
|
}
|
|
@@ -9323,9 +9781,18 @@ var Endpoint = class {
|
|
|
9323
9781
|
pipelineId: this._pipelineId
|
|
9324
9782
|
};
|
|
9325
9783
|
}
|
|
9784
|
+
async liveIngress(stream) {
|
|
9785
|
+
if (!this._baseUrl || !this._client) {
|
|
9786
|
+
return Promise.reject("endpoint not connected, use connect() before ingress()");
|
|
9787
|
+
}
|
|
9788
|
+
const job = new Whip(stream, async () => {
|
|
9789
|
+
return this.session();
|
|
9790
|
+
}, this._client, this._requestLogger);
|
|
9791
|
+
return job.start();
|
|
9792
|
+
}
|
|
9326
9793
|
async upload(params) {
|
|
9327
9794
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9328
|
-
return Promise.reject("endpoint not connected, use
|
|
9795
|
+
return Promise.reject("endpoint not connected, use connect() before upload()");
|
|
9329
9796
|
}
|
|
9330
9797
|
params = await resolve(params);
|
|
9331
9798
|
if (!params.mimeType) {
|
|
@@ -9344,7 +9811,7 @@ var Endpoint = class {
|
|
|
9344
9811
|
}
|
|
9345
9812
|
async loadFrom(location) {
|
|
9346
9813
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9347
|
-
throw new Error("endpoint not connected, use
|
|
9814
|
+
throw new Error("endpoint not connected, use connect() before loadFrom()");
|
|
9348
9815
|
}
|
|
9349
9816
|
await this._limit.acquire();
|
|
9350
9817
|
this.updateState();
|
|
@@ -9357,6 +9824,21 @@ var Endpoint = class {
|
|
|
9357
9824
|
this.jobStatus(job, statusCode);
|
|
9358
9825
|
});
|
|
9359
9826
|
}
|
|
9827
|
+
async loadLiveIngress(ingressId) {
|
|
9828
|
+
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9829
|
+
throw new Error("endpoint not connected, use connect() before loadLiveIngress()");
|
|
9830
|
+
}
|
|
9831
|
+
await this._limit.acquire();
|
|
9832
|
+
this.updateState();
|
|
9833
|
+
const job = new LoadLiveIngressJob(ingressId, async () => {
|
|
9834
|
+
return this.session();
|
|
9835
|
+
}, this._client, this._requestLogger);
|
|
9836
|
+
return job.start(() => {
|
|
9837
|
+
this.jobDone(job);
|
|
9838
|
+
}, (statusCode) => {
|
|
9839
|
+
this.jobStatus(job, statusCode);
|
|
9840
|
+
});
|
|
9841
|
+
}
|
|
9360
9842
|
// noinspection TypeScriptValidateTypes
|
|
9361
9843
|
async connect() {
|
|
9362
9844
|
if (this._client) {
|
|
@@ -9394,6 +9876,9 @@ var Endpoint = class {
|
|
|
9394
9876
|
}
|
|
9395
9877
|
this._requestLogger.debug("after PATCH %s", stop_url);
|
|
9396
9878
|
}
|
|
9879
|
+
if (!this._ingressEventWs && this._ingressEventHandler) {
|
|
9880
|
+
await this.startIngressWs();
|
|
9881
|
+
}
|
|
9397
9882
|
return result;
|
|
9398
9883
|
}
|
|
9399
9884
|
jobDone(job) {
|
|
@@ -9556,7 +10041,7 @@ var _EyePopPlot = class _EyePopPlot {
|
|
|
9556
10041
|
}
|
|
9557
10042
|
}
|
|
9558
10043
|
}
|
|
9559
|
-
object(obj, x_scale, y_scale) {
|
|
10044
|
+
object(obj, x_scale = 1, y_scale = 1) {
|
|
9560
10045
|
const context = this._context;
|
|
9561
10046
|
const x = obj.x * x_scale;
|
|
9562
10047
|
const y = obj.y * y_scale;
|