@eyepop.ai/eyepop 0.10.0 → 0.12.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 +78 -23
- package/dist/eyepop.min.js +1 -1
- package/dist/eyepop.min.js.LICENSE.txt +18 -0
- package/dist/index.d.mts +40 -12
- package/dist/index.d.ts +40 -12
- package/dist/index.js +590 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +580 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -2
package/dist/index.mjs
CHANGED
|
@@ -8915,7 +8915,7 @@ var AbstractJob = class {
|
|
|
8915
8915
|
return Promise.reject("abstract class");
|
|
8916
8916
|
}
|
|
8917
8917
|
start(done, status) {
|
|
8918
|
-
this._responseStream = new Promise(async (
|
|
8918
|
+
this._responseStream = new Promise(async (resolve, reject) => {
|
|
8919
8919
|
try {
|
|
8920
8920
|
let retries = 1;
|
|
8921
8921
|
while (true) {
|
|
@@ -8944,7 +8944,7 @@ var AbstractJob = class {
|
|
|
8944
8944
|
reject(`response body is empty`);
|
|
8945
8945
|
break;
|
|
8946
8946
|
} else {
|
|
8947
|
-
|
|
8947
|
+
resolve(response.body);
|
|
8948
8948
|
break;
|
|
8949
8949
|
}
|
|
8950
8950
|
} catch (error) {
|
|
@@ -9035,6 +9035,39 @@ var LoadFromJob = class extends AbstractJob {
|
|
|
9035
9035
|
return response;
|
|
9036
9036
|
}
|
|
9037
9037
|
};
|
|
9038
|
+
var LoadLiveIngressJob = class extends AbstractJob {
|
|
9039
|
+
constructor(ingressId, getSession, client, requestLogger) {
|
|
9040
|
+
super(getSession, client, requestLogger);
|
|
9041
|
+
this._ingressId = ingressId;
|
|
9042
|
+
}
|
|
9043
|
+
get [Symbol.toStringTag]() {
|
|
9044
|
+
return "loadLiveIngressJob";
|
|
9045
|
+
}
|
|
9046
|
+
async startJob() {
|
|
9047
|
+
const body = {
|
|
9048
|
+
"sourceType": "LIVE_INGRESS",
|
|
9049
|
+
"liveIngressId": this._ingressId
|
|
9050
|
+
};
|
|
9051
|
+
const session = await this._getSession();
|
|
9052
|
+
const headers = {
|
|
9053
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9054
|
+
"Accept": "application/jsonl",
|
|
9055
|
+
"Content-Type": "application/json"
|
|
9056
|
+
};
|
|
9057
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9058
|
+
this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._ingressId);
|
|
9059
|
+
const response = await this._client.fetch(patchUrl, {
|
|
9060
|
+
headers,
|
|
9061
|
+
method: "PATCH",
|
|
9062
|
+
body: JSON.stringify(body),
|
|
9063
|
+
signal: this._controller.signal,
|
|
9064
|
+
// @ts-ignore
|
|
9065
|
+
dispatcher: this._dispatcher
|
|
9066
|
+
});
|
|
9067
|
+
this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._ingressId);
|
|
9068
|
+
return response;
|
|
9069
|
+
}
|
|
9070
|
+
};
|
|
9038
9071
|
|
|
9039
9072
|
// src/shims/http_client.ts
|
|
9040
9073
|
var createHttpClient;
|
|
@@ -9203,45 +9236,391 @@ var Semaphore = class {
|
|
|
9203
9236
|
}
|
|
9204
9237
|
};
|
|
9205
9238
|
|
|
9206
|
-
//
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9239
|
+
// node_modules/uuid/dist/esm-node/rng.js
|
|
9240
|
+
import crypto from "crypto";
|
|
9241
|
+
var rnds8Pool = new Uint8Array(256);
|
|
9242
|
+
var poolPtr = rnds8Pool.length;
|
|
9243
|
+
function rng() {
|
|
9244
|
+
if (poolPtr > rnds8Pool.length - 16) {
|
|
9245
|
+
crypto.randomFillSync(rnds8Pool);
|
|
9246
|
+
poolPtr = 0;
|
|
9247
|
+
}
|
|
9248
|
+
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
9249
|
+
}
|
|
9250
|
+
|
|
9251
|
+
// node_modules/uuid/dist/esm-node/stringify.js
|
|
9252
|
+
var byteToHex = [];
|
|
9253
|
+
for (let i = 0; i < 256; ++i) {
|
|
9254
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
9255
|
+
}
|
|
9256
|
+
function unsafeStringify(arr, offset = 0) {
|
|
9257
|
+
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]];
|
|
9258
|
+
}
|
|
9259
|
+
|
|
9260
|
+
// node_modules/uuid/dist/esm-node/native.js
|
|
9261
|
+
import crypto2 from "crypto";
|
|
9262
|
+
var native_default = {
|
|
9263
|
+
randomUUID: crypto2.randomUUID
|
|
9264
|
+
};
|
|
9265
|
+
|
|
9266
|
+
// node_modules/uuid/dist/esm-node/v4.js
|
|
9267
|
+
function v4(options, buf, offset) {
|
|
9268
|
+
if (native_default.randomUUID && !buf && !options) {
|
|
9269
|
+
return native_default.randomUUID();
|
|
9270
|
+
}
|
|
9271
|
+
options = options || {};
|
|
9272
|
+
const rnds = options.random || (options.rng || rng)();
|
|
9273
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
9274
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
9275
|
+
if (buf) {
|
|
9276
|
+
offset = offset || 0;
|
|
9277
|
+
for (let i = 0; i < 16; ++i) {
|
|
9278
|
+
buf[offset + i] = rnds[i];
|
|
9279
|
+
}
|
|
9280
|
+
return buf;
|
|
9281
|
+
}
|
|
9282
|
+
return unsafeStringify(rnds);
|
|
9283
|
+
}
|
|
9284
|
+
var v4_default = v4;
|
|
9285
|
+
|
|
9286
|
+
// src/web_rtc_base.ts
|
|
9287
|
+
var WebRtcBase = class {
|
|
9288
|
+
constructor(getSession, client, requestLogger) {
|
|
9289
|
+
this._pc = null;
|
|
9290
|
+
this._getSession = getSession;
|
|
9291
|
+
this._client = client;
|
|
9292
|
+
this._requestLogger = requestLogger;
|
|
9293
|
+
this._eTag = "";
|
|
9294
|
+
this._queuedCandidates = [];
|
|
9295
|
+
this._offerData = null;
|
|
9296
|
+
}
|
|
9297
|
+
static linkToIceServers(links) {
|
|
9298
|
+
const servers = links !== null ? links.split(", ").map((link) => {
|
|
9299
|
+
const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
9300
|
+
if (!m) {
|
|
9301
|
+
return null;
|
|
9302
|
+
}
|
|
9303
|
+
const iceServer = {
|
|
9304
|
+
urls: [m[1]],
|
|
9305
|
+
username: Whip.unquoteCredential(m[3]),
|
|
9306
|
+
credential: Whip.unquoteCredential(m[4])
|
|
9307
|
+
// credentialType: m[3]? "password" : undefined
|
|
9308
|
+
};
|
|
9309
|
+
return iceServer;
|
|
9310
|
+
}) : [];
|
|
9311
|
+
return servers.filter(function(el) {
|
|
9312
|
+
return el != null;
|
|
9313
|
+
});
|
|
9314
|
+
}
|
|
9315
|
+
static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
|
|
9316
|
+
const sections = answer.split("m=");
|
|
9317
|
+
for (let i = 0; i < sections.length; i++) {
|
|
9318
|
+
const section = sections[i];
|
|
9319
|
+
if (section.startsWith("video")) {
|
|
9320
|
+
sections[i] = Whip.setVideoBitrate(Whip.setCodec(section, videoCodec), videoBitrate);
|
|
9321
|
+
} else if (section.startsWith("audio")) {
|
|
9322
|
+
sections[i] = Whip.setAudioBitrate(Whip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9218
9323
|
}
|
|
9219
9324
|
}
|
|
9220
|
-
|
|
9221
|
-
}
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9325
|
+
return sections.join("m=");
|
|
9326
|
+
}
|
|
9327
|
+
static setCodec(section, codec) {
|
|
9328
|
+
const lines = section.split("\r\n");
|
|
9329
|
+
const lines2 = [];
|
|
9330
|
+
const payloadFormats = [];
|
|
9331
|
+
for (const line of lines) {
|
|
9332
|
+
if (!line.startsWith("a=rtpmap:")) {
|
|
9333
|
+
lines2.push(line);
|
|
9334
|
+
} else {
|
|
9335
|
+
if (codec && line.toLowerCase().includes(codec)) {
|
|
9336
|
+
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9337
|
+
lines2.push(line);
|
|
9338
|
+
}
|
|
9339
|
+
}
|
|
9226
9340
|
}
|
|
9227
|
-
const
|
|
9228
|
-
const
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9341
|
+
const lines3 = [];
|
|
9342
|
+
for (const line of lines2) {
|
|
9343
|
+
if (line.startsWith("a=fmtp:")) {
|
|
9344
|
+
if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
|
|
9345
|
+
lines3.push(line);
|
|
9346
|
+
}
|
|
9347
|
+
} else if (line.startsWith("a=rtcp-fb:")) {
|
|
9348
|
+
if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
|
|
9349
|
+
lines3.push(line);
|
|
9350
|
+
}
|
|
9234
9351
|
} else {
|
|
9235
|
-
|
|
9352
|
+
lines3.push(line);
|
|
9353
|
+
}
|
|
9354
|
+
}
|
|
9355
|
+
return lines3.join("\r\n");
|
|
9356
|
+
}
|
|
9357
|
+
static setVideoBitrate(section, bitrate) {
|
|
9358
|
+
let lines = section.split("\r\n");
|
|
9359
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9360
|
+
if (lines[i].startsWith("c=")) {
|
|
9361
|
+
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9362
|
+
break;
|
|
9363
|
+
}
|
|
9364
|
+
}
|
|
9365
|
+
return lines.join("\r\n");
|
|
9366
|
+
}
|
|
9367
|
+
static setAudioBitrate(section, bitrate, voice) {
|
|
9368
|
+
let opusPayloadFormat = "";
|
|
9369
|
+
let lines = section.split("\r\n");
|
|
9370
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9371
|
+
if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
|
|
9372
|
+
opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
|
|
9373
|
+
break;
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
9376
|
+
if (opusPayloadFormat === "") {
|
|
9377
|
+
return section;
|
|
9378
|
+
}
|
|
9379
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9380
|
+
if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
|
|
9381
|
+
if (voice) {
|
|
9382
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
|
|
9383
|
+
} else {
|
|
9384
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
|
|
9385
|
+
}
|
|
9236
9386
|
}
|
|
9237
|
-
stream = fs.createReadStream(params.filePath);
|
|
9238
9387
|
}
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9388
|
+
return lines.join("\r\n");
|
|
9389
|
+
}
|
|
9390
|
+
static parseOffer(offer) {
|
|
9391
|
+
let medias = [];
|
|
9392
|
+
let iceUfrag = "";
|
|
9393
|
+
let icePwd = "";
|
|
9394
|
+
for (const line of offer.split("\r\n")) {
|
|
9395
|
+
if (line.startsWith("m=")) {
|
|
9396
|
+
medias.push(line.slice("m=".length));
|
|
9397
|
+
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9398
|
+
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9399
|
+
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9400
|
+
icePwd = line.slice("a=ice-pwd:".length);
|
|
9401
|
+
}
|
|
9402
|
+
}
|
|
9403
|
+
return {
|
|
9404
|
+
iceUfrag,
|
|
9405
|
+
icePwd,
|
|
9406
|
+
medias
|
|
9407
|
+
};
|
|
9408
|
+
}
|
|
9409
|
+
static generateSdpFragment(offerData, candidates) {
|
|
9410
|
+
const candidatesByMedia = /* @__PURE__ */ new Map();
|
|
9411
|
+
for (const candidate of candidates) {
|
|
9412
|
+
if (candidate.sdpMLineIndex !== null) {
|
|
9413
|
+
const mid2 = candidate.sdpMLineIndex;
|
|
9414
|
+
let matched = candidatesByMedia.get(mid2);
|
|
9415
|
+
if (matched === void 0) {
|
|
9416
|
+
matched = [];
|
|
9417
|
+
candidatesByMedia.set(mid2, matched);
|
|
9418
|
+
}
|
|
9419
|
+
matched.push(candidate);
|
|
9420
|
+
}
|
|
9421
|
+
}
|
|
9422
|
+
let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
|
|
9423
|
+
let mid = 0;
|
|
9424
|
+
for (const media of offerData.medias) {
|
|
9425
|
+
let matched = candidatesByMedia.get(mid);
|
|
9426
|
+
if (matched !== void 0) {
|
|
9427
|
+
frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
|
|
9428
|
+
for (const candidate of matched) {
|
|
9429
|
+
frag += "a=" + candidate.candidate + "\r\n";
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
mid++;
|
|
9433
|
+
}
|
|
9434
|
+
return frag;
|
|
9435
|
+
}
|
|
9436
|
+
static unquoteCredential(v) {
|
|
9437
|
+
if (!v) {
|
|
9438
|
+
return "";
|
|
9439
|
+
}
|
|
9440
|
+
return JSON.parse(`"${v}"`);
|
|
9441
|
+
}
|
|
9442
|
+
};
|
|
9443
|
+
|
|
9444
|
+
// src/whip.ts
|
|
9445
|
+
var Whip = class _Whip extends WebRtcBase {
|
|
9446
|
+
constructor(stream, getSession, client, requestLogger) {
|
|
9447
|
+
super(getSession, client, requestLogger);
|
|
9448
|
+
this._ingressId = v4_default().toString();
|
|
9449
|
+
this._stream = stream;
|
|
9450
|
+
}
|
|
9451
|
+
ingressId() {
|
|
9452
|
+
if (!this._ingressId) {
|
|
9453
|
+
throw new Error("not initialized");
|
|
9454
|
+
}
|
|
9455
|
+
return this._ingressId;
|
|
9456
|
+
}
|
|
9457
|
+
async start() {
|
|
9458
|
+
const session = await this._getSession();
|
|
9459
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9460
|
+
this._requestLogger.debug("before GET: %s", ingressUrl);
|
|
9461
|
+
const headers = {
|
|
9462
|
+
"Authorization": `Bearer ${session.accessToken}`
|
|
9463
|
+
};
|
|
9464
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9465
|
+
headers,
|
|
9466
|
+
method: "GET"
|
|
9467
|
+
});
|
|
9468
|
+
if (response.status >= 300) {
|
|
9469
|
+
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9470
|
+
}
|
|
9471
|
+
return this.onIceServers(response);
|
|
9472
|
+
}
|
|
9473
|
+
async onIceServers(response) {
|
|
9474
|
+
if (!this._stream) {
|
|
9475
|
+
throw new Error("onIceServers no stream");
|
|
9476
|
+
}
|
|
9477
|
+
const stream = this._stream;
|
|
9478
|
+
const pc = new RTCPeerConnection({
|
|
9479
|
+
iceServers: _Whip.linkToIceServers(response.headers.get("Link"))
|
|
9480
|
+
});
|
|
9481
|
+
this._pc = pc;
|
|
9482
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9483
|
+
return new Promise(async (resolve, reject) => {
|
|
9484
|
+
pc.oniceconnectionstatechange = () => {
|
|
9485
|
+
switch (pc.iceConnectionState) {
|
|
9486
|
+
case "failed":
|
|
9487
|
+
case "disconnected":
|
|
9488
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9489
|
+
break;
|
|
9490
|
+
case "connected":
|
|
9491
|
+
resolve(this);
|
|
9492
|
+
break;
|
|
9493
|
+
}
|
|
9494
|
+
};
|
|
9495
|
+
stream.getTracks().forEach((track) => {
|
|
9496
|
+
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9497
|
+
pc.addTrack(track, stream);
|
|
9498
|
+
});
|
|
9499
|
+
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9500
|
+
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9501
|
+
pc.addTrack(trackEvent.track, stream);
|
|
9502
|
+
});
|
|
9503
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
9504
|
+
});
|
|
9505
|
+
}
|
|
9506
|
+
async onLocalCandidate(evt) {
|
|
9507
|
+
if (evt.candidate !== null) {
|
|
9508
|
+
if (this._eTag === "") {
|
|
9509
|
+
this._queuedCandidates.push(evt.candidate);
|
|
9510
|
+
} else {
|
|
9511
|
+
await this.sendLocalCandidates([evt.candidate]);
|
|
9512
|
+
}
|
|
9513
|
+
}
|
|
9514
|
+
return this;
|
|
9515
|
+
}
|
|
9516
|
+
async onLocalOffer(offer) {
|
|
9517
|
+
if (!this._pc) {
|
|
9518
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9519
|
+
}
|
|
9520
|
+
if (!offer.sdp) {
|
|
9521
|
+
throw new Error("onLocalOffer no sdp");
|
|
9522
|
+
}
|
|
9523
|
+
this._offerData = _Whip.parseOffer(offer.sdp);
|
|
9524
|
+
await this._pc.setLocalDescription(offer);
|
|
9525
|
+
const session = await this._getSession();
|
|
9526
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9527
|
+
this._requestLogger.debug("before GET: %s", ingressUrl);
|
|
9528
|
+
const headers = {
|
|
9529
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9530
|
+
"Content-Type": "application/sdp"
|
|
9531
|
+
};
|
|
9532
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9533
|
+
headers,
|
|
9534
|
+
method: "POST",
|
|
9535
|
+
body: offer.sdp
|
|
9536
|
+
});
|
|
9537
|
+
if (response.status != 201) {
|
|
9538
|
+
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9539
|
+
}
|
|
9540
|
+
this._eTag = response.headers.get("ETag") ?? "";
|
|
9541
|
+
return this.onRemoteAnswer(new RTCSessionDescription({
|
|
9542
|
+
type: "answer",
|
|
9543
|
+
sdp: await response.text()
|
|
9544
|
+
}));
|
|
9545
|
+
}
|
|
9546
|
+
async onRemoteAnswer(answer) {
|
|
9547
|
+
if (!this._pc) {
|
|
9548
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9549
|
+
}
|
|
9550
|
+
answer = new RTCSessionDescription({
|
|
9551
|
+
type: "answer",
|
|
9552
|
+
sdp: _Whip.editAnswer(
|
|
9553
|
+
answer.sdp,
|
|
9554
|
+
"h264/90000",
|
|
9555
|
+
void 0,
|
|
9556
|
+
5e3,
|
|
9557
|
+
void 0,
|
|
9558
|
+
true
|
|
9559
|
+
)
|
|
9560
|
+
});
|
|
9561
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
9562
|
+
if (this._queuedCandidates.length !== 0) {
|
|
9563
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9564
|
+
this._queuedCandidates = [];
|
|
9565
|
+
}
|
|
9566
|
+
return this;
|
|
9567
|
+
}
|
|
9568
|
+
async sendLocalCandidates(candidates) {
|
|
9569
|
+
if (!this._offerData) {
|
|
9570
|
+
throw new Error("sendLocalCandidates no offerData");
|
|
9571
|
+
}
|
|
9572
|
+
const session = await this._getSession();
|
|
9573
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9574
|
+
this._requestLogger.debug("before PATCH: %s", ingressUrl);
|
|
9575
|
+
const headers = {
|
|
9576
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9577
|
+
"Content-Type": "application/trickle-ice-sdpfrag",
|
|
9578
|
+
"If-Match": this._eTag
|
|
9579
|
+
};
|
|
9580
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9581
|
+
headers,
|
|
9582
|
+
method: "PATCH",
|
|
9583
|
+
body: _Whip.generateSdpFragment(this._offerData, candidates)
|
|
9584
|
+
});
|
|
9585
|
+
if (response.status != 204) {
|
|
9586
|
+
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9587
|
+
}
|
|
9588
|
+
return this;
|
|
9589
|
+
}
|
|
9590
|
+
async close() {
|
|
9591
|
+
const pc = this._pc;
|
|
9592
|
+
const stream = this._stream;
|
|
9593
|
+
this._stream = null;
|
|
9594
|
+
this._pc = null;
|
|
9595
|
+
if (stream) {
|
|
9596
|
+
const tracks = stream.getTracks();
|
|
9597
|
+
tracks.forEach((track) => {
|
|
9598
|
+
track.stop();
|
|
9599
|
+
});
|
|
9600
|
+
}
|
|
9601
|
+
if (pc) {
|
|
9602
|
+
return pc.close();
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
};
|
|
9606
|
+
|
|
9607
|
+
// src/shims/local_file.ts
|
|
9608
|
+
var resolvePath;
|
|
9609
|
+
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
9610
|
+
resolvePath = async (source) => {
|
|
9611
|
+
throw new DOMException("resolving a path to a file is not supported in browser");
|
|
9612
|
+
};
|
|
9613
|
+
} else {
|
|
9614
|
+
resolvePath = async (source) => {
|
|
9615
|
+
const mime = require_mime_types();
|
|
9616
|
+
const filehandle = __require("fs/promises");
|
|
9617
|
+
const fd = await filehandle.open(source.path, "r");
|
|
9618
|
+
const stream = fd.createReadStream();
|
|
9619
|
+
const mimeType = mime.lookup(source.path) || "application/octet-stream";
|
|
9620
|
+
return {
|
|
9621
|
+
stream,
|
|
9622
|
+
mimeType
|
|
9243
9623
|
};
|
|
9244
|
-
return params;
|
|
9245
9624
|
};
|
|
9246
9625
|
}
|
|
9247
9626
|
|
|
@@ -9258,6 +9637,8 @@ var Endpoint = class {
|
|
|
9258
9637
|
this._client = null;
|
|
9259
9638
|
this._state = "Idle" /* Idle */;
|
|
9260
9639
|
this._stateChangeHandler = null;
|
|
9640
|
+
this._ingressEventHandler = null;
|
|
9641
|
+
this._ingressEventWs = null;
|
|
9261
9642
|
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
9262
9643
|
let rootLogger;
|
|
9263
9644
|
if (options.logger) {
|
|
@@ -9272,6 +9653,51 @@ var Endpoint = class {
|
|
|
9272
9653
|
this._stateChangeHandler = handler;
|
|
9273
9654
|
return this;
|
|
9274
9655
|
}
|
|
9656
|
+
async startIngressWs() {
|
|
9657
|
+
if (this._ingressEventWs || !this._baseUrl || !this._client) {
|
|
9658
|
+
return;
|
|
9659
|
+
}
|
|
9660
|
+
try {
|
|
9661
|
+
const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
|
|
9662
|
+
const headers = {
|
|
9663
|
+
"Authorization": await this.authorizationHeader()
|
|
9664
|
+
};
|
|
9665
|
+
this._requestLogger.debug("before GET %s", getTokenUrl);
|
|
9666
|
+
let response = await this._client.fetch(getTokenUrl, { headers });
|
|
9667
|
+
if (response.status == 401) {
|
|
9668
|
+
this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
|
|
9669
|
+
this._token = null;
|
|
9670
|
+
const headers2 = {
|
|
9671
|
+
"Authorization": await this.authorizationHeader()
|
|
9672
|
+
};
|
|
9673
|
+
this.updateState("FetchConfig" /* FetchConfig */);
|
|
9674
|
+
response = await this._client.fetch(getTokenUrl, { headers: headers2 });
|
|
9675
|
+
}
|
|
9676
|
+
if (response.status != 200) {
|
|
9677
|
+
const message = await response.text();
|
|
9678
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9679
|
+
}
|
|
9680
|
+
const wsAuthToken = await response.json();
|
|
9681
|
+
const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
|
|
9682
|
+
this._ingressEventWs = new WebSocket(wsUrl);
|
|
9683
|
+
this._ingressEventWs.addEventListener("message", (event) => {
|
|
9684
|
+
const ingressEvent = JSON.parse(event.data);
|
|
9685
|
+
if (this._ingressEventHandler) {
|
|
9686
|
+
this._ingressEventHandler(ingressEvent);
|
|
9687
|
+
}
|
|
9688
|
+
});
|
|
9689
|
+
} finally {
|
|
9690
|
+
this.updateState();
|
|
9691
|
+
}
|
|
9692
|
+
}
|
|
9693
|
+
onIngressEvent(handler) {
|
|
9694
|
+
this._ingressEventHandler = handler;
|
|
9695
|
+
this.startIngressWs().then(() => {
|
|
9696
|
+
}).catch((reason) => {
|
|
9697
|
+
this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
|
|
9698
|
+
});
|
|
9699
|
+
return this;
|
|
9700
|
+
}
|
|
9275
9701
|
state() {
|
|
9276
9702
|
return this._state;
|
|
9277
9703
|
}
|
|
@@ -9304,39 +9730,130 @@ var Endpoint = class {
|
|
|
9304
9730
|
pipelineId: this._pipelineId
|
|
9305
9731
|
};
|
|
9306
9732
|
}
|
|
9307
|
-
async
|
|
9733
|
+
async liveIngress(stream) {
|
|
9734
|
+
if (!this._baseUrl || !this._client) {
|
|
9735
|
+
return Promise.reject("endpoint not connected, use connect() before ingress()");
|
|
9736
|
+
}
|
|
9737
|
+
const whip = new Whip(stream, async () => {
|
|
9738
|
+
return this.session();
|
|
9739
|
+
}, this._client, this._requestLogger);
|
|
9740
|
+
return whip.start();
|
|
9741
|
+
}
|
|
9742
|
+
async process(source) {
|
|
9743
|
+
if (source.file !== void 0) {
|
|
9744
|
+
return this.uploadFile(source);
|
|
9745
|
+
} else if (source.stream !== void 0) {
|
|
9746
|
+
return this.uploadStream(source);
|
|
9747
|
+
} else if (source.path !== void 0) {
|
|
9748
|
+
return this.uploadPath(source);
|
|
9749
|
+
} else if (source.url !== void 0) {
|
|
9750
|
+
return this.loadFrom(source);
|
|
9751
|
+
} else if (source.ingressId !== void 0) {
|
|
9752
|
+
return this.loadLiveIngress(source);
|
|
9753
|
+
} else {
|
|
9754
|
+
return Promise.reject("unknown source type");
|
|
9755
|
+
}
|
|
9756
|
+
}
|
|
9757
|
+
async uploadFile(source) {
|
|
9308
9758
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9309
|
-
return Promise.reject("endpoint not connected, use
|
|
9759
|
+
return Promise.reject("endpoint not connected, use connect() before upload()");
|
|
9310
9760
|
}
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9761
|
+
await this._limit.acquire();
|
|
9762
|
+
try {
|
|
9763
|
+
this.updateState();
|
|
9764
|
+
const job = new UploadJob(source.file, source.file.type, async () => {
|
|
9765
|
+
return this.session();
|
|
9766
|
+
}, this._client, this._requestLogger);
|
|
9767
|
+
return job.start(() => {
|
|
9768
|
+
this.jobDone(job);
|
|
9769
|
+
}, (statusCode) => {
|
|
9770
|
+
this.jobStatus(job, statusCode);
|
|
9771
|
+
});
|
|
9772
|
+
} catch (e) {
|
|
9773
|
+
this._limit.release();
|
|
9774
|
+
throw e;
|
|
9775
|
+
}
|
|
9776
|
+
}
|
|
9777
|
+
async uploadStream(source) {
|
|
9778
|
+
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9779
|
+
return Promise.reject("endpoint not connected, use connect() before upload()");
|
|
9314
9780
|
}
|
|
9315
9781
|
await this._limit.acquire();
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9323
|
-
|
|
9324
|
-
|
|
9782
|
+
try {
|
|
9783
|
+
this.updateState();
|
|
9784
|
+
const job = new UploadJob(source.stream, source.mimeType, async () => {
|
|
9785
|
+
return this.session();
|
|
9786
|
+
}, this._client, this._requestLogger);
|
|
9787
|
+
return job.start(() => {
|
|
9788
|
+
this.jobDone(job);
|
|
9789
|
+
}, (statusCode) => {
|
|
9790
|
+
this.jobStatus(job, statusCode);
|
|
9791
|
+
});
|
|
9792
|
+
} catch (e) {
|
|
9793
|
+
this._limit.release();
|
|
9794
|
+
throw e;
|
|
9795
|
+
}
|
|
9325
9796
|
}
|
|
9326
|
-
async
|
|
9797
|
+
async uploadPath(source) {
|
|
9327
9798
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9328
|
-
throw new Error("endpoint not connected, use
|
|
9799
|
+
throw new Error("endpoint not connected, use connect() before process()");
|
|
9329
9800
|
}
|
|
9330
9801
|
await this._limit.acquire();
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
this.
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9802
|
+
try {
|
|
9803
|
+
this.updateState();
|
|
9804
|
+
const streamSource = await resolvePath(source);
|
|
9805
|
+
const job = new UploadJob(streamSource.stream, streamSource.mimeType, async () => {
|
|
9806
|
+
return this.session();
|
|
9807
|
+
}, this._client, this._requestLogger);
|
|
9808
|
+
return job.start(() => {
|
|
9809
|
+
this.jobDone(job);
|
|
9810
|
+
}, (statusCode) => {
|
|
9811
|
+
this.jobStatus(job, statusCode);
|
|
9812
|
+
});
|
|
9813
|
+
} catch (e) {
|
|
9814
|
+
this._limit.release();
|
|
9815
|
+
throw e;
|
|
9816
|
+
}
|
|
9817
|
+
}
|
|
9818
|
+
async loadFrom(source) {
|
|
9819
|
+
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9820
|
+
throw new Error("endpoint not connected, use connect() before loadFrom()");
|
|
9821
|
+
}
|
|
9822
|
+
await this._limit.acquire();
|
|
9823
|
+
try {
|
|
9824
|
+
this.updateState();
|
|
9825
|
+
const job = new LoadFromJob(source.url, async () => {
|
|
9826
|
+
return this.session();
|
|
9827
|
+
}, this._client, this._requestLogger);
|
|
9828
|
+
return job.start(() => {
|
|
9829
|
+
this.jobDone(job);
|
|
9830
|
+
}, (statusCode) => {
|
|
9831
|
+
this.jobStatus(job, statusCode);
|
|
9832
|
+
});
|
|
9833
|
+
} catch (e) {
|
|
9834
|
+
this._limit.release();
|
|
9835
|
+
throw e;
|
|
9836
|
+
}
|
|
9837
|
+
}
|
|
9838
|
+
async loadLiveIngress(source) {
|
|
9839
|
+
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9840
|
+
throw new Error("endpoint not connected, use connect() before loadLiveIngress()");
|
|
9841
|
+
}
|
|
9842
|
+
await this._limit.acquire();
|
|
9843
|
+
try {
|
|
9844
|
+
this.updateState();
|
|
9845
|
+
const job = new LoadLiveIngressJob(source.ingressId, async () => {
|
|
9846
|
+
return this.session();
|
|
9847
|
+
}, this._client, this._requestLogger);
|
|
9848
|
+
return job.start(() => {
|
|
9849
|
+
this.jobDone(job);
|
|
9850
|
+
}, (statusCode) => {
|
|
9851
|
+
this.jobStatus(job, statusCode);
|
|
9852
|
+
});
|
|
9853
|
+
} catch (e) {
|
|
9854
|
+
this._limit.release();
|
|
9855
|
+
throw e;
|
|
9856
|
+
}
|
|
9340
9857
|
}
|
|
9341
9858
|
// noinspection TypeScriptValidateTypes
|
|
9342
9859
|
async connect() {
|
|
@@ -9375,6 +9892,9 @@ var Endpoint = class {
|
|
|
9375
9892
|
}
|
|
9376
9893
|
this._requestLogger.debug("after PATCH %s", stop_url);
|
|
9377
9894
|
}
|
|
9895
|
+
if (!this._ingressEventWs && this._ingressEventHandler) {
|
|
9896
|
+
await this.startIngressWs();
|
|
9897
|
+
}
|
|
9378
9898
|
return result;
|
|
9379
9899
|
}
|
|
9380
9900
|
jobDone(job) {
|
|
@@ -9537,7 +10057,7 @@ var _EyePopPlot = class _EyePopPlot {
|
|
|
9537
10057
|
}
|
|
9538
10058
|
}
|
|
9539
10059
|
}
|
|
9540
|
-
object(obj, x_scale, y_scale) {
|
|
10060
|
+
object(obj, x_scale = 1, y_scale = 1) {
|
|
9541
10061
|
const context = this._context;
|
|
9542
10062
|
const x = obj.x * x_scale;
|
|
9543
10063
|
const y = obj.y * y_scale;
|