@eyepop.ai/eyepop 1.17.5 → 1.18.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/dist/eyepop.index.d.mts +16 -24
- package/dist/eyepop.index.d.ts +16 -24
- package/dist/eyepop.index.js +722 -734
- package/dist/eyepop.index.js.map +1 -1
- package/dist/eyepop.index.mjs +721 -734
- package/dist/eyepop.index.mjs.map +1 -1
- package/dist/eyepop.min.js +1 -1
- package/package.json +1 -1
package/dist/eyepop.index.js
CHANGED
|
@@ -8674,6 +8674,7 @@ __export(index_exports, {
|
|
|
8674
8674
|
LoadFromAssetUuidJob: () => LoadFromAssetUuidJob,
|
|
8675
8675
|
LoadFromJob: () => LoadFromJob,
|
|
8676
8676
|
LoadLiveIngressJob: () => LoadLiveIngressJob,
|
|
8677
|
+
LoadMediaStreamJob: () => LoadMediaStreamJob,
|
|
8677
8678
|
ModelExportStatus: () => ModelExportStatus,
|
|
8678
8679
|
ModelFormat: () => ModelFormat,
|
|
8679
8680
|
ModelPrecisionType: () => ModelPrecisionType,
|
|
@@ -8953,748 +8954,724 @@ var ContourType = /* @__PURE__ */ ((ContourType2) => {
|
|
|
8953
8954
|
return ContourType2;
|
|
8954
8955
|
})(ContourType || {});
|
|
8955
8956
|
|
|
8956
|
-
// worker/
|
|
8957
|
-
var
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8957
|
+
// worker/webrtc_whip.ts
|
|
8958
|
+
var import_uuid = require("uuid");
|
|
8959
|
+
|
|
8960
|
+
// worker/webrtc_base.ts
|
|
8961
|
+
var import_path = __toESM(require("path"));
|
|
8962
|
+
var WebrtcBase = class _WebrtcBase {
|
|
8963
|
+
constructor(getSession, client, ingressId, urlBasePath, is_pipeline_direct, requestLogger) {
|
|
8961
8964
|
this._getSession = getSession;
|
|
8962
|
-
this._params = params ?? null;
|
|
8963
8965
|
this._client = client;
|
|
8964
8966
|
this._requestLogger = requestLogger;
|
|
8967
|
+
this._ingressId = ingressId;
|
|
8968
|
+
this._urlPath = `${urlBasePath}/${this._ingressId}`;
|
|
8969
|
+
this._is_pipeline_direct = is_pipeline_direct;
|
|
8970
|
+
this._pc = null;
|
|
8971
|
+
this._eTag = "";
|
|
8972
|
+
this._location = null;
|
|
8973
|
+
this._queuedCandidates = [];
|
|
8974
|
+
this._offerData = null;
|
|
8965
8975
|
}
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8976
|
+
async close() {
|
|
8977
|
+
const pc = this._pc;
|
|
8978
|
+
this._pc = null;
|
|
8979
|
+
if (pc) {
|
|
8980
|
+
return pc.close();
|
|
8969
8981
|
}
|
|
8970
|
-
return Stream.iterFromReadableStream(this._responseStream, this._controller, async (event) => {
|
|
8971
|
-
return await this.onEvent(event);
|
|
8972
|
-
});
|
|
8973
8982
|
}
|
|
8974
|
-
|
|
8975
|
-
return
|
|
8983
|
+
ingressId() {
|
|
8984
|
+
return this._ingressId;
|
|
8976
8985
|
}
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8986
|
+
gresUrl(session, location = null) {
|
|
8987
|
+
let urlPath;
|
|
8988
|
+
if (this._is_pipeline_direct) {
|
|
8989
|
+
if (!session.pipelineId) {
|
|
8990
|
+
throw new Error("cannot connect with is_pipeline_direct=true but !session.pipelineId");
|
|
8991
|
+
}
|
|
8992
|
+
urlPath = import_path.default.join("pipelines", session.pipelineId, this._urlPath);
|
|
8993
|
+
} else {
|
|
8994
|
+
urlPath = this._urlPath;
|
|
8980
8995
|
}
|
|
8981
|
-
|
|
8996
|
+
if (location) {
|
|
8997
|
+
urlPath = import_path.default.join(urlPath, location);
|
|
8998
|
+
}
|
|
8999
|
+
let baseUrl;
|
|
9000
|
+
if (session.baseUrl?.endsWith("/")) {
|
|
9001
|
+
baseUrl = session.baseUrl;
|
|
9002
|
+
} else {
|
|
9003
|
+
baseUrl = session.baseUrl + "/";
|
|
9004
|
+
}
|
|
9005
|
+
return new URL(urlPath, baseUrl);
|
|
8982
9006
|
}
|
|
8983
|
-
|
|
8984
|
-
this.
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
} else {
|
|
9003
|
-
reject(`response ${response.status}: ${response.statusText}`);
|
|
9004
|
-
break;
|
|
9005
|
-
}
|
|
9006
|
-
} else if (response.status != 200) {
|
|
9007
|
-
reject(`upload error ${response.status}: ${await response.text()}`);
|
|
9008
|
-
break;
|
|
9009
|
-
} else if (response.body) {
|
|
9010
|
-
resolve(response.body);
|
|
9011
|
-
break;
|
|
9012
|
-
} else {
|
|
9013
|
-
const text = await response.text();
|
|
9014
|
-
if (text) {
|
|
9015
|
-
resolve(readableStreamFromString(text));
|
|
9016
|
-
break;
|
|
9017
|
-
} else {
|
|
9018
|
-
reject("response body is empty");
|
|
9019
|
-
break;
|
|
9020
|
-
}
|
|
9021
|
-
}
|
|
9022
|
-
} catch (error) {
|
|
9023
|
-
if (retries--) {
|
|
9024
|
-
this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
|
|
9025
|
-
status(404);
|
|
9026
|
-
} else {
|
|
9027
|
-
status(500);
|
|
9028
|
-
reject(error);
|
|
9029
|
-
break;
|
|
9030
|
-
}
|
|
9031
|
-
}
|
|
9032
|
-
}
|
|
9033
|
-
} catch (reason) {
|
|
9034
|
-
reject(reason);
|
|
9035
|
-
} finally {
|
|
9036
|
-
done();
|
|
9037
|
-
}
|
|
9007
|
+
async onLocalOffer(offer) {
|
|
9008
|
+
if (!this._pc) {
|
|
9009
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9010
|
+
}
|
|
9011
|
+
if (!offer.sdp) {
|
|
9012
|
+
throw new Error("onLocalOffer no sdp");
|
|
9013
|
+
}
|
|
9014
|
+
this._offerData = _WebrtcBase.parseOffer(offer.sdp);
|
|
9015
|
+
await this._pc.setLocalDescription(offer);
|
|
9016
|
+
const session = await this._getSession();
|
|
9017
|
+
const ingressUrl = this.gresUrl(session);
|
|
9018
|
+
const headers = {
|
|
9019
|
+
...session.authenticationHeaders(),
|
|
9020
|
+
"Content-Type": "application/sdp"
|
|
9021
|
+
};
|
|
9022
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9023
|
+
headers,
|
|
9024
|
+
method: "POST",
|
|
9025
|
+
body: offer.sdp
|
|
9038
9026
|
});
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
this.
|
|
9027
|
+
if (response.status >= 300) {
|
|
9028
|
+
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9029
|
+
}
|
|
9030
|
+
this._eTag = response.headers.get("ETag") ?? "";
|
|
9031
|
+
this._location = response.headers.get("Location");
|
|
9032
|
+
return await this.onRemoteAnswer(new RTCSessionDescription({
|
|
9033
|
+
type: "answer",
|
|
9034
|
+
sdp: await response.text()
|
|
9035
|
+
}));
|
|
9043
9036
|
}
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9037
|
+
async sendLocalCandidates(candidates) {
|
|
9038
|
+
if (!this._offerData) {
|
|
9039
|
+
throw new Error("sendLocalCandidates no offerData");
|
|
9040
|
+
}
|
|
9041
|
+
const session = await this._getSession();
|
|
9042
|
+
const ingressUrl = this.gresUrl(session, this._location);
|
|
9043
|
+
const headers = {
|
|
9044
|
+
...session.authenticationHeaders(),
|
|
9045
|
+
"Content-Type": "application/trickle-ice-sdpfrag",
|
|
9046
|
+
"If-Match": this._eTag
|
|
9047
|
+
};
|
|
9048
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9049
|
+
headers,
|
|
9050
|
+
method: "PATCH",
|
|
9051
|
+
body: _WebrtcBase.generateSdpFragment(this._offerData, candidates)
|
|
9052
|
+
});
|
|
9053
|
+
if (response.status >= 300) {
|
|
9054
|
+
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9055
|
+
}
|
|
9056
|
+
return this;
|
|
9049
9057
|
}
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9058
|
+
async onLocalCandidate(evt) {
|
|
9059
|
+
if (evt.candidate !== null) {
|
|
9060
|
+
if (this._eTag === "") {
|
|
9061
|
+
this._queuedCandidates.push(evt.candidate);
|
|
9062
|
+
} else {
|
|
9063
|
+
await this.sendLocalCandidates([evt.candidate]);
|
|
9064
|
+
}
|
|
9065
|
+
}
|
|
9066
|
+
return this;
|
|
9057
9067
|
}
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9068
|
+
static linkToIceServers(links) {
|
|
9069
|
+
const servers = links !== null ? links.split(", ").map((link) => {
|
|
9070
|
+
let m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
9071
|
+
if (!m) {
|
|
9072
|
+
m = link.match(/^(.+?); rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
9062
9073
|
}
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
return Promise.reject("session.baseUrl must not ne null");
|
|
9074
|
+
if (!m) {
|
|
9075
|
+
return null;
|
|
9066
9076
|
}
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9077
|
+
const iceServer = {
|
|
9078
|
+
urls: [m[1]],
|
|
9079
|
+
username: WebrtcWhip.unquoteCredential(m[3]),
|
|
9080
|
+
credential: WebrtcWhip.unquoteCredential(m[4])
|
|
9081
|
+
// credentialType: m[3]? "password" : undefined
|
|
9082
|
+
};
|
|
9083
|
+
return iceServer;
|
|
9084
|
+
}) : [];
|
|
9085
|
+
return servers.filter(function(el) {
|
|
9086
|
+
return el != null;
|
|
9087
|
+
});
|
|
9088
|
+
}
|
|
9089
|
+
static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
|
|
9090
|
+
const sections = answer.split("m=");
|
|
9091
|
+
for (let i = 0; i < sections.length; i++) {
|
|
9092
|
+
const section = sections[i];
|
|
9093
|
+
if (section.startsWith("video")) {
|
|
9094
|
+
sections[i] = WebrtcWhip.setVideoBitrate(WebrtcWhip.setCodec(section, videoCodec), videoBitrate);
|
|
9095
|
+
} else if (section.startsWith("audio")) {
|
|
9096
|
+
sections[i] = WebrtcWhip.setAudioBitrate(WebrtcWhip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9097
|
+
}
|
|
9098
|
+
}
|
|
9099
|
+
return sections.join("m=");
|
|
9100
|
+
}
|
|
9101
|
+
static setCodec(section, codec) {
|
|
9102
|
+
const lines = section.split("\r\n");
|
|
9103
|
+
const lines2 = [];
|
|
9104
|
+
const payloadFormats = [];
|
|
9105
|
+
for (const line of lines) {
|
|
9106
|
+
if (!line.startsWith("a=rtpmap:")) {
|
|
9107
|
+
lines2.push(line);
|
|
9090
9108
|
} else {
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
"Content-Type": this._mimeType
|
|
9095
|
-
};
|
|
9096
|
-
if (this._size) {
|
|
9097
|
-
headers["Content-Length"] = `${this._size}`;
|
|
9109
|
+
if (codec && line.toLowerCase().includes(codec)) {
|
|
9110
|
+
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9111
|
+
lines2.push(line);
|
|
9098
9112
|
}
|
|
9099
|
-
request = this._client.fetch(postUrl, {
|
|
9100
|
-
headers,
|
|
9101
|
-
method: "POST",
|
|
9102
|
-
body: this._uploadStream,
|
|
9103
|
-
signal: this._controller.signal,
|
|
9104
|
-
// @ts-ignore
|
|
9105
|
-
duplex: "half",
|
|
9106
|
-
eyepop: { responseStreaming: true }
|
|
9107
|
-
});
|
|
9108
9113
|
}
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9114
|
+
}
|
|
9115
|
+
const lines3 = [];
|
|
9116
|
+
for (const line of lines2) {
|
|
9117
|
+
if (line.startsWith("a=fmtp:")) {
|
|
9118
|
+
if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
|
|
9119
|
+
lines3.push(line);
|
|
9112
9120
|
}
|
|
9113
|
-
}
|
|
9114
|
-
|
|
9115
|
-
|
|
9121
|
+
} else if (line.startsWith("a=rtcp-fb:")) {
|
|
9122
|
+
if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
|
|
9123
|
+
lines3.push(line);
|
|
9124
|
+
}
|
|
9125
|
+
} else {
|
|
9126
|
+
lines3.push(line);
|
|
9127
|
+
}
|
|
9116
9128
|
}
|
|
9117
|
-
return
|
|
9129
|
+
return lines3.join("\r\n");
|
|
9118
9130
|
}
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9131
|
+
static setVideoBitrate(section, bitrate) {
|
|
9132
|
+
let lines = section.split("\r\n");
|
|
9133
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9134
|
+
if (lines[i].startsWith("c=")) {
|
|
9135
|
+
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9136
|
+
break;
|
|
9137
|
+
}
|
|
9123
9138
|
}
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
const paramBlob = new Blob([params], { type: "application/json" });
|
|
9145
|
-
const formData = new FormData();
|
|
9146
|
-
const fileBlob = await new Response(this._uploadStream).blob();
|
|
9147
|
-
formData.append("params", paramBlob);
|
|
9148
|
-
formData.append("file", fileBlob);
|
|
9149
|
-
const headers = {
|
|
9150
|
-
...session.authenticationHeaders(),
|
|
9151
|
-
Accept: "application/jsonl"
|
|
9152
|
-
};
|
|
9153
|
-
response = await this._client.fetch(postUrl, {
|
|
9154
|
-
headers,
|
|
9155
|
-
method: "POST",
|
|
9156
|
-
body: formData,
|
|
9157
|
-
signal: this._controller.signal,
|
|
9158
|
-
// @ts-ignore
|
|
9159
|
-
duplex: "half",
|
|
9160
|
-
eyepop: { responseStreaming: true }
|
|
9161
|
-
});
|
|
9162
|
-
} else {
|
|
9163
|
-
const headers = {
|
|
9164
|
-
...session.authenticationHeaders(),
|
|
9165
|
-
Accept: "application/jsonl",
|
|
9166
|
-
"Content-Type": this._mimeType
|
|
9167
|
-
};
|
|
9168
|
-
if (this._size) {
|
|
9169
|
-
headers["Content-Length"] = `${this._size}`;
|
|
9139
|
+
return lines.join("\r\n");
|
|
9140
|
+
}
|
|
9141
|
+
static setAudioBitrate(section, bitrate, voice) {
|
|
9142
|
+
let opusPayloadFormat = "";
|
|
9143
|
+
let lines = section.split("\r\n");
|
|
9144
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9145
|
+
if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
|
|
9146
|
+
opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
|
|
9147
|
+
break;
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
if (opusPayloadFormat === "") {
|
|
9151
|
+
return section;
|
|
9152
|
+
}
|
|
9153
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9154
|
+
if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
|
|
9155
|
+
if (voice) {
|
|
9156
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
|
|
9157
|
+
} else {
|
|
9158
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
|
|
9170
9159
|
}
|
|
9171
|
-
response = await this._client.fetch(postUrl, {
|
|
9172
|
-
headers,
|
|
9173
|
-
method: "POST",
|
|
9174
|
-
body: this._uploadStream,
|
|
9175
|
-
signal: this._controller.signal,
|
|
9176
|
-
// @ts-ignore
|
|
9177
|
-
duplex: "half"
|
|
9178
|
-
});
|
|
9179
9160
|
}
|
|
9180
9161
|
}
|
|
9181
|
-
return
|
|
9182
|
-
}
|
|
9183
|
-
};
|
|
9184
|
-
var LoadFromJob = class extends AbstractJob {
|
|
9185
|
-
constructor(location, params, getSession, client, requestLogger) {
|
|
9186
|
-
super(params, getSession, client, requestLogger);
|
|
9187
|
-
this._location = location;
|
|
9188
|
-
}
|
|
9189
|
-
get [Symbol.toStringTag]() {
|
|
9190
|
-
return "loadFromJob";
|
|
9162
|
+
return lines.join("\r\n");
|
|
9191
9163
|
}
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9164
|
+
static parseOffer(offer) {
|
|
9165
|
+
let medias = [];
|
|
9166
|
+
let iceUfrag = "";
|
|
9167
|
+
let icePwd = "";
|
|
9168
|
+
for (const line of offer.split("\r\n")) {
|
|
9169
|
+
if (line.startsWith("m=")) {
|
|
9170
|
+
medias.push(line.slice("m=".length));
|
|
9171
|
+
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9172
|
+
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9173
|
+
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9174
|
+
icePwd = line.slice("a=ice-pwd:".length);
|
|
9175
|
+
}
|
|
9196
9176
|
}
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
};
|
|
9202
|
-
const headers = {
|
|
9203
|
-
...session.authenticationHeaders(),
|
|
9204
|
-
Accept: "application/jsonl",
|
|
9205
|
-
"Content-Type": "application/json"
|
|
9177
|
+
return {
|
|
9178
|
+
iceUfrag,
|
|
9179
|
+
icePwd,
|
|
9180
|
+
medias
|
|
9206
9181
|
};
|
|
9207
|
-
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9208
|
-
return await this._client.fetch(patchUrl, {
|
|
9209
|
-
headers,
|
|
9210
|
-
method: "PATCH",
|
|
9211
|
-
body: JSON.stringify(body),
|
|
9212
|
-
signal: this._controller.signal,
|
|
9213
|
-
// @ts-ignore
|
|
9214
|
-
eyepop: { responseStreaming: true }
|
|
9215
|
-
});
|
|
9216
|
-
}
|
|
9217
|
-
};
|
|
9218
|
-
var LoadFromAssetUuidJob = class extends AbstractJob {
|
|
9219
|
-
constructor(assetUuid, params, getSession, client, requestLogger) {
|
|
9220
|
-
super(params, getSession, client, requestLogger);
|
|
9221
|
-
this._assetUuid = assetUuid;
|
|
9222
9182
|
}
|
|
9223
|
-
|
|
9224
|
-
|
|
9183
|
+
static generateSdpFragment(offerData, candidates) {
|
|
9184
|
+
const candidatesByMedia = /* @__PURE__ */ new Map();
|
|
9185
|
+
for (const candidate of candidates) {
|
|
9186
|
+
if (candidate.sdpMLineIndex !== null) {
|
|
9187
|
+
const mid2 = candidate.sdpMLineIndex;
|
|
9188
|
+
let matched = candidatesByMedia.get(mid2);
|
|
9189
|
+
if (matched === void 0) {
|
|
9190
|
+
matched = [];
|
|
9191
|
+
candidatesByMedia.set(mid2, matched);
|
|
9192
|
+
}
|
|
9193
|
+
matched.push(candidate);
|
|
9194
|
+
}
|
|
9195
|
+
}
|
|
9196
|
+
let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
|
|
9197
|
+
let mid = 0;
|
|
9198
|
+
for (const media of offerData.medias) {
|
|
9199
|
+
let matched = candidatesByMedia.get(mid);
|
|
9200
|
+
if (matched !== void 0) {
|
|
9201
|
+
frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
|
|
9202
|
+
for (const candidate of matched) {
|
|
9203
|
+
frag += "a=" + candidate.candidate + "\r\n";
|
|
9204
|
+
}
|
|
9205
|
+
}
|
|
9206
|
+
mid++;
|
|
9207
|
+
}
|
|
9208
|
+
return frag;
|
|
9225
9209
|
}
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
return Promise.reject("session.baseUrl must not ne null");
|
|
9210
|
+
static unquoteCredential(v) {
|
|
9211
|
+
if (!v) {
|
|
9212
|
+
return "";
|
|
9230
9213
|
}
|
|
9231
|
-
|
|
9232
|
-
sourceType: "ASSET_UUID",
|
|
9233
|
-
assetUuid: this._assetUuid,
|
|
9234
|
-
params: this._params
|
|
9235
|
-
};
|
|
9236
|
-
const headers = {
|
|
9237
|
-
...session.authenticationHeaders(),
|
|
9238
|
-
Accept: "application/jsonl",
|
|
9239
|
-
"Content-Type": "application/json"
|
|
9240
|
-
};
|
|
9241
|
-
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9242
|
-
return await this._client.fetch(patchUrl, {
|
|
9243
|
-
headers,
|
|
9244
|
-
method: "PATCH",
|
|
9245
|
-
body: JSON.stringify(body),
|
|
9246
|
-
signal: this._controller.signal,
|
|
9247
|
-
// @ts-ignore
|
|
9248
|
-
eyepop: { responseStreaming: true }
|
|
9249
|
-
});
|
|
9214
|
+
return JSON.parse(`"${v}"`);
|
|
9250
9215
|
}
|
|
9251
9216
|
};
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
return "loadLiveIngressJob";
|
|
9217
|
+
|
|
9218
|
+
// worker/webrtc_whip.ts
|
|
9219
|
+
var WebrtcWhip = class extends WebrtcBase {
|
|
9220
|
+
constructor(stream, getSession, client, is_pipeline_direct, requestLogger) {
|
|
9221
|
+
super(getSession, client, (0, import_uuid.v4)().toString(), "liveIngress/whip", is_pipeline_direct, requestLogger);
|
|
9222
|
+
this._stream = stream;
|
|
9259
9223
|
}
|
|
9260
|
-
async
|
|
9224
|
+
async start() {
|
|
9261
9225
|
const session = await this._getSession();
|
|
9262
|
-
|
|
9263
|
-
|
|
9226
|
+
const ingressUrl = this.gresUrl(session);
|
|
9227
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9228
|
+
headers: session.authenticationHeaders(),
|
|
9229
|
+
method: "GET"
|
|
9230
|
+
});
|
|
9231
|
+
if (response.status >= 300) {
|
|
9232
|
+
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9264
9233
|
}
|
|
9265
|
-
|
|
9266
|
-
sourceType: "LIVE_INGRESS",
|
|
9267
|
-
liveIngressId: this._ingressId,
|
|
9268
|
-
params: this._params
|
|
9269
|
-
};
|
|
9270
|
-
const headers = {
|
|
9271
|
-
...session.authenticationHeaders(),
|
|
9272
|
-
Accept: "application/jsonl",
|
|
9273
|
-
"Content-Type": "application/json"
|
|
9274
|
-
};
|
|
9275
|
-
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=preempt&processing=sync`;
|
|
9276
|
-
return await this._client.fetch(patchUrl, {
|
|
9277
|
-
headers,
|
|
9278
|
-
method: "PATCH",
|
|
9279
|
-
body: JSON.stringify(body),
|
|
9280
|
-
signal: this._controller.signal,
|
|
9281
|
-
// @ts-ignore
|
|
9282
|
-
eyepop: { responseStreaming: true }
|
|
9283
|
-
});
|
|
9284
|
-
}
|
|
9285
|
-
};
|
|
9286
|
-
|
|
9287
|
-
// worker/webrtc_whip.ts
|
|
9288
|
-
var import_uuid = require("uuid");
|
|
9289
|
-
|
|
9290
|
-
// worker/webrtc_base.ts
|
|
9291
|
-
var import_path = __toESM(require("path"));
|
|
9292
|
-
var WebrtcBase = class _WebrtcBase {
|
|
9293
|
-
constructor(getSession, client, ingressId, urlBasePath, requestLogger) {
|
|
9294
|
-
this._getSession = getSession;
|
|
9295
|
-
this._client = client;
|
|
9296
|
-
this._requestLogger = requestLogger;
|
|
9297
|
-
this._ingressId = ingressId;
|
|
9298
|
-
this._urlPath = `${urlBasePath}/${this._ingressId}`;
|
|
9299
|
-
this._pc = null;
|
|
9300
|
-
this._eTag = "";
|
|
9301
|
-
this._location = null;
|
|
9302
|
-
this._queuedCandidates = [];
|
|
9303
|
-
this._offerData = null;
|
|
9304
|
-
}
|
|
9305
|
-
async close() {
|
|
9306
|
-
const pc = this._pc;
|
|
9307
|
-
this._pc = null;
|
|
9308
|
-
if (pc) {
|
|
9309
|
-
return pc.close();
|
|
9310
|
-
}
|
|
9311
|
-
}
|
|
9312
|
-
ingressId() {
|
|
9313
|
-
return this._ingressId;
|
|
9234
|
+
return await this.onIceServers(response);
|
|
9314
9235
|
}
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
urlPath = import_path.default.join(this._urlPath, location);
|
|
9319
|
-
} else {
|
|
9320
|
-
urlPath = this._urlPath;
|
|
9321
|
-
}
|
|
9322
|
-
let baseUrl;
|
|
9323
|
-
if (session.baseUrl?.endsWith("/")) {
|
|
9324
|
-
baseUrl = session.baseUrl;
|
|
9236
|
+
async stream() {
|
|
9237
|
+
if (this._stream) {
|
|
9238
|
+
return Promise.resolve(this._stream);
|
|
9325
9239
|
} else {
|
|
9326
|
-
|
|
9240
|
+
return Promise.reject("fetching stream failed");
|
|
9327
9241
|
}
|
|
9328
|
-
return new URL(urlPath, baseUrl);
|
|
9329
9242
|
}
|
|
9330
|
-
async
|
|
9243
|
+
async onRemoteAnswer(answer) {
|
|
9331
9244
|
if (!this._pc) {
|
|
9332
9245
|
throw new Error("onLocalOffer no peer connection");
|
|
9333
9246
|
}
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
await this._pc.setLocalDescription(offer);
|
|
9339
|
-
const session = await this._getSession();
|
|
9340
|
-
const ingressUrl = this.gresUrl(session);
|
|
9341
|
-
const headers = {
|
|
9342
|
-
...session.authenticationHeaders(),
|
|
9343
|
-
"Content-Type": "application/sdp"
|
|
9344
|
-
};
|
|
9345
|
-
const response = await this._client.fetch(ingressUrl, {
|
|
9346
|
-
headers,
|
|
9347
|
-
method: "POST",
|
|
9348
|
-
body: offer.sdp
|
|
9349
|
-
});
|
|
9350
|
-
if (response.status != 201) {
|
|
9351
|
-
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9247
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
9248
|
+
if (this._queuedCandidates.length !== 0) {
|
|
9249
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9250
|
+
this._queuedCandidates = [];
|
|
9352
9251
|
}
|
|
9353
|
-
this
|
|
9354
|
-
this._location = response.headers.get("Location");
|
|
9355
|
-
return await this.onRemoteAnswer(new RTCSessionDescription({
|
|
9356
|
-
type: "answer",
|
|
9357
|
-
sdp: await response.text()
|
|
9358
|
-
}));
|
|
9252
|
+
return this;
|
|
9359
9253
|
}
|
|
9360
|
-
async
|
|
9361
|
-
if (!this.
|
|
9362
|
-
throw new Error("
|
|
9254
|
+
async onIceServers(response) {
|
|
9255
|
+
if (!this._stream) {
|
|
9256
|
+
throw new Error("onIceServers no stream");
|
|
9363
9257
|
}
|
|
9364
|
-
const
|
|
9365
|
-
const
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9258
|
+
const stream = this._stream;
|
|
9259
|
+
const pc = new RTCPeerConnection({
|
|
9260
|
+
iceServers: WebrtcBase.linkToIceServers(response.headers.get("Link"))
|
|
9261
|
+
});
|
|
9262
|
+
this._pc = pc;
|
|
9263
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9264
|
+
return new Promise(async (resolve, reject) => {
|
|
9265
|
+
pc.oniceconnectionstatechange = () => {
|
|
9266
|
+
switch (pc.iceConnectionState) {
|
|
9267
|
+
case "failed":
|
|
9268
|
+
case "disconnected":
|
|
9269
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9270
|
+
break;
|
|
9271
|
+
case "connected":
|
|
9272
|
+
resolve(this);
|
|
9273
|
+
break;
|
|
9274
|
+
}
|
|
9275
|
+
};
|
|
9276
|
+
stream.getTracks().forEach((track) => {
|
|
9277
|
+
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9278
|
+
pc.addTrack(track, stream);
|
|
9279
|
+
});
|
|
9280
|
+
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9281
|
+
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9282
|
+
pc.addTrack(trackEvent.track, stream);
|
|
9283
|
+
});
|
|
9284
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
9375
9285
|
});
|
|
9376
|
-
if (response.status != 204) {
|
|
9377
|
-
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9378
|
-
}
|
|
9379
|
-
return this;
|
|
9380
9286
|
}
|
|
9381
|
-
async
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9287
|
+
async close() {
|
|
9288
|
+
const stream = this._stream;
|
|
9289
|
+
this._stream = null;
|
|
9290
|
+
if (stream) {
|
|
9291
|
+
const tracks = stream.getTracks();
|
|
9292
|
+
tracks.forEach((track) => {
|
|
9293
|
+
track.stop();
|
|
9294
|
+
});
|
|
9388
9295
|
}
|
|
9389
|
-
return
|
|
9296
|
+
return super.close();
|
|
9390
9297
|
}
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
};
|
|
9403
|
-
return iceServer;
|
|
9404
|
-
}) : [];
|
|
9405
|
-
return servers.filter(function(el) {
|
|
9406
|
-
return el != null;
|
|
9407
|
-
});
|
|
9298
|
+
};
|
|
9299
|
+
|
|
9300
|
+
// worker/jobs.ts
|
|
9301
|
+
var AbstractJob = class {
|
|
9302
|
+
constructor(params, getSession, client, requestLogger) {
|
|
9303
|
+
this._responseStream = null;
|
|
9304
|
+
this._controller = new AbortController();
|
|
9305
|
+
this._getSession = getSession;
|
|
9306
|
+
this._params = params ?? null;
|
|
9307
|
+
this._client = client;
|
|
9308
|
+
this._requestLogger = requestLogger;
|
|
9408
9309
|
}
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
const section = sections[i];
|
|
9413
|
-
if (section.startsWith("video")) {
|
|
9414
|
-
sections[i] = WebrtcWhip.setVideoBitrate(WebrtcWhip.setCodec(section, videoCodec), videoBitrate);
|
|
9415
|
-
} else if (section.startsWith("audio")) {
|
|
9416
|
-
sections[i] = WebrtcWhip.setAudioBitrate(WebrtcWhip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9417
|
-
}
|
|
9310
|
+
[Symbol.asyncIterator]() {
|
|
9311
|
+
if (!this._responseStream) {
|
|
9312
|
+
throw Error("logical bug");
|
|
9418
9313
|
}
|
|
9419
|
-
return
|
|
9314
|
+
return Stream.iterFromReadableStream(this._responseStream, this._controller, async (event) => {
|
|
9315
|
+
return await this.onEvent(event);
|
|
9316
|
+
});
|
|
9420
9317
|
}
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
lines2.push(line);
|
|
9428
|
-
} else {
|
|
9429
|
-
if (codec && line.toLowerCase().includes(codec)) {
|
|
9430
|
-
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9431
|
-
lines2.push(line);
|
|
9432
|
-
}
|
|
9433
|
-
}
|
|
9318
|
+
async startJob() {
|
|
9319
|
+
return Promise.reject("abstract class");
|
|
9320
|
+
}
|
|
9321
|
+
async onEvent(event) {
|
|
9322
|
+
if (event.type == "error") {
|
|
9323
|
+
return Promise.reject(`Error event for source ${event.source_id}: ${event.message}`);
|
|
9434
9324
|
}
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9325
|
+
return Promise.resolve();
|
|
9326
|
+
}
|
|
9327
|
+
start(done, status) {
|
|
9328
|
+
this._responseStream = new Promise(async (resolve, reject) => {
|
|
9329
|
+
try {
|
|
9330
|
+
let retries = 1;
|
|
9331
|
+
while (true) {
|
|
9332
|
+
try {
|
|
9333
|
+
const response = await this.startJob();
|
|
9334
|
+
if (response.status == 401) {
|
|
9335
|
+
status(response.status);
|
|
9336
|
+
if (retries--) {
|
|
9337
|
+
this._requestLogger.info("received 401 response, attempt to reauthorize once");
|
|
9338
|
+
} else {
|
|
9339
|
+
reject(`response ${response.status}: ${response.statusText}`);
|
|
9340
|
+
break;
|
|
9341
|
+
}
|
|
9342
|
+
} else if (response.status == 404) {
|
|
9343
|
+
status(response.status);
|
|
9344
|
+
if (retries--) {
|
|
9345
|
+
this._requestLogger.info("received 404 response, attempt to restart pop");
|
|
9346
|
+
} else {
|
|
9347
|
+
reject(`response ${response.status}: ${response.statusText}`);
|
|
9348
|
+
break;
|
|
9349
|
+
}
|
|
9350
|
+
} else if (response.status != 200) {
|
|
9351
|
+
reject(`upload error ${response.status}: ${await response.text()}`);
|
|
9352
|
+
break;
|
|
9353
|
+
} else if (response.body) {
|
|
9354
|
+
resolve(response.body);
|
|
9355
|
+
break;
|
|
9356
|
+
} else {
|
|
9357
|
+
const text = await response.text();
|
|
9358
|
+
if (text) {
|
|
9359
|
+
resolve(readableStreamFromString(text));
|
|
9360
|
+
break;
|
|
9361
|
+
} else {
|
|
9362
|
+
reject("response body is empty");
|
|
9363
|
+
break;
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
9366
|
+
} catch (error) {
|
|
9367
|
+
if (retries--) {
|
|
9368
|
+
this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
|
|
9369
|
+
status(404);
|
|
9370
|
+
} else {
|
|
9371
|
+
status(500);
|
|
9372
|
+
reject(error);
|
|
9373
|
+
break;
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
9444
9376
|
}
|
|
9445
|
-
}
|
|
9446
|
-
|
|
9377
|
+
} catch (reason) {
|
|
9378
|
+
reject(reason);
|
|
9379
|
+
} finally {
|
|
9380
|
+
done();
|
|
9447
9381
|
}
|
|
9448
|
-
}
|
|
9449
|
-
return
|
|
9382
|
+
});
|
|
9383
|
+
return this;
|
|
9450
9384
|
}
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
for (let i = 0; i < lines.length; i++) {
|
|
9454
|
-
if (lines[i].startsWith("c=")) {
|
|
9455
|
-
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9456
|
-
break;
|
|
9457
|
-
}
|
|
9458
|
-
}
|
|
9459
|
-
return lines.join("\r\n");
|
|
9385
|
+
cancel() {
|
|
9386
|
+
this._controller.abort("cancelled");
|
|
9460
9387
|
}
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9388
|
+
};
|
|
9389
|
+
AbstractJob.n = 0;
|
|
9390
|
+
var UploadJob = class extends AbstractJob {
|
|
9391
|
+
get [Symbol.toStringTag]() {
|
|
9392
|
+
return "uploadJob";
|
|
9393
|
+
}
|
|
9394
|
+
constructor(stream, mimeType, size, videoMode, params, getSession, client, requestLogger) {
|
|
9395
|
+
super(params, getSession, client, requestLogger);
|
|
9396
|
+
this._uploadStream = stream;
|
|
9397
|
+
this._mimeType = mimeType;
|
|
9398
|
+
this._size = size;
|
|
9399
|
+
this._videoMode = videoMode;
|
|
9400
|
+
this._needsFullDuplex = !client.isFullDuplex() && mimeType.startsWith("video/") && videoMode == "stream" /* STREAM */;
|
|
9401
|
+
}
|
|
9402
|
+
async onEvent(event) {
|
|
9403
|
+
if (event.type == "prepared") {
|
|
9404
|
+
if (!event.source_id) {
|
|
9405
|
+
return Promise.reject("did not get a prepared sourceId to simulate full duplex");
|
|
9468
9406
|
}
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9407
|
+
const session = await this._getSession();
|
|
9408
|
+
if (!session.baseUrl) {
|
|
9409
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9410
|
+
}
|
|
9411
|
+
let request;
|
|
9412
|
+
const videoModeQuery = this._videoMode ? `&videoMode=${this._videoMode}` : "";
|
|
9413
|
+
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=async&sourceId=${event.source_id}${videoModeQuery}`;
|
|
9414
|
+
if (this._params) {
|
|
9415
|
+
const params = JSON.stringify(this._params);
|
|
9416
|
+
const paramBlob = new Blob([params], { type: "application/json" });
|
|
9417
|
+
const formData = new FormData();
|
|
9418
|
+
const fileBlob = await new Response(this._uploadStream).blob();
|
|
9419
|
+
formData.append("params", paramBlob);
|
|
9420
|
+
formData.append("file", fileBlob);
|
|
9421
|
+
const headers = {
|
|
9422
|
+
...session.authenticationHeaders(),
|
|
9423
|
+
Accept: "application/jsonl"
|
|
9424
|
+
};
|
|
9425
|
+
request = this._client.fetch(postUrl, {
|
|
9426
|
+
headers,
|
|
9427
|
+
method: "POST",
|
|
9428
|
+
body: formData,
|
|
9429
|
+
signal: this._controller.signal,
|
|
9430
|
+
// @ts-ignore
|
|
9431
|
+
duplex: "half",
|
|
9432
|
+
eyepop: { responseStreaming: true }
|
|
9433
|
+
});
|
|
9434
|
+
} else {
|
|
9435
|
+
const headers = {
|
|
9436
|
+
...session.authenticationHeaders(),
|
|
9437
|
+
Accept: "application/jsonl",
|
|
9438
|
+
"Content-Type": this._mimeType
|
|
9439
|
+
};
|
|
9440
|
+
if (this._size) {
|
|
9441
|
+
headers["Content-Length"] = `${this._size}`;
|
|
9479
9442
|
}
|
|
9443
|
+
request = this._client.fetch(postUrl, {
|
|
9444
|
+
headers,
|
|
9445
|
+
method: "POST",
|
|
9446
|
+
body: this._uploadStream,
|
|
9447
|
+
signal: this._controller.signal,
|
|
9448
|
+
// @ts-ignore
|
|
9449
|
+
duplex: "half",
|
|
9450
|
+
eyepop: { responseStreaming: true }
|
|
9451
|
+
});
|
|
9480
9452
|
}
|
|
9453
|
+
request.then(async (value) => {
|
|
9454
|
+
if (value.status != 204) {
|
|
9455
|
+
this._requestLogger.debug(`unexpected status ${value.status} (${await value.text()}) for POST ${postUrl}`);
|
|
9456
|
+
}
|
|
9457
|
+
}).catch((reason) => {
|
|
9458
|
+
this._requestLogger.debug(`error ${reason} for POST ${postUrl}`);
|
|
9459
|
+
});
|
|
9481
9460
|
}
|
|
9482
|
-
return
|
|
9483
|
-
}
|
|
9484
|
-
static parseOffer(offer) {
|
|
9485
|
-
let medias = [];
|
|
9486
|
-
let iceUfrag = "";
|
|
9487
|
-
let icePwd = "";
|
|
9488
|
-
for (const line of offer.split("\r\n")) {
|
|
9489
|
-
if (line.startsWith("m=")) {
|
|
9490
|
-
medias.push(line.slice("m=".length));
|
|
9491
|
-
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9492
|
-
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9493
|
-
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9494
|
-
icePwd = line.slice("a=ice-pwd:".length);
|
|
9495
|
-
}
|
|
9496
|
-
}
|
|
9497
|
-
return {
|
|
9498
|
-
iceUfrag,
|
|
9499
|
-
icePwd,
|
|
9500
|
-
medias
|
|
9501
|
-
};
|
|
9461
|
+
return Promise.resolve();
|
|
9502
9462
|
}
|
|
9503
|
-
|
|
9504
|
-
const
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
const mid2 = candidate.sdpMLineIndex;
|
|
9508
|
-
let matched = candidatesByMedia.get(mid2);
|
|
9509
|
-
if (matched === void 0) {
|
|
9510
|
-
matched = [];
|
|
9511
|
-
candidatesByMedia.set(mid2, matched);
|
|
9512
|
-
}
|
|
9513
|
-
matched.push(candidate);
|
|
9514
|
-
}
|
|
9463
|
+
async startJob() {
|
|
9464
|
+
const session = await this._getSession();
|
|
9465
|
+
if (!session.baseUrl) {
|
|
9466
|
+
return Promise.reject("session.baseUrl must not be null");
|
|
9515
9467
|
}
|
|
9516
|
-
let
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9468
|
+
let response;
|
|
9469
|
+
if (this._needsFullDuplex) {
|
|
9470
|
+
const prepareUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/prepareSource?timeout=10s`;
|
|
9471
|
+
const headers = {
|
|
9472
|
+
...session.authenticationHeaders(),
|
|
9473
|
+
Accept: "application/jsonl"
|
|
9474
|
+
};
|
|
9475
|
+
response = await this._client.fetch(prepareUrl, {
|
|
9476
|
+
headers,
|
|
9477
|
+
method: "POST",
|
|
9478
|
+
signal: this._controller.signal,
|
|
9479
|
+
// @ts-ignore
|
|
9480
|
+
duplex: "half",
|
|
9481
|
+
eyepop: { responseStreaming: true }
|
|
9482
|
+
});
|
|
9483
|
+
} else {
|
|
9484
|
+
const videoModeQuery = this._videoMode ? `&videoMode=${this._videoMode}` : "";
|
|
9485
|
+
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync${videoModeQuery}`;
|
|
9486
|
+
if (this._params) {
|
|
9487
|
+
const params = JSON.stringify(this._params);
|
|
9488
|
+
const paramBlob = new Blob([params], { type: "application/json" });
|
|
9489
|
+
const formData = new FormData();
|
|
9490
|
+
const fileBlob = await new Response(this._uploadStream).blob();
|
|
9491
|
+
formData.append("params", paramBlob);
|
|
9492
|
+
formData.append("file", fileBlob);
|
|
9493
|
+
const headers = {
|
|
9494
|
+
...session.authenticationHeaders(),
|
|
9495
|
+
Accept: "application/jsonl"
|
|
9496
|
+
};
|
|
9497
|
+
response = await this._client.fetch(postUrl, {
|
|
9498
|
+
headers,
|
|
9499
|
+
method: "POST",
|
|
9500
|
+
body: formData,
|
|
9501
|
+
signal: this._controller.signal,
|
|
9502
|
+
// @ts-ignore
|
|
9503
|
+
duplex: "half",
|
|
9504
|
+
eyepop: { responseStreaming: true }
|
|
9505
|
+
});
|
|
9506
|
+
} else {
|
|
9507
|
+
const headers = {
|
|
9508
|
+
...session.authenticationHeaders(),
|
|
9509
|
+
Accept: "application/jsonl",
|
|
9510
|
+
"Content-Type": this._mimeType
|
|
9511
|
+
};
|
|
9512
|
+
if (this._size) {
|
|
9513
|
+
headers["Content-Length"] = `${this._size}`;
|
|
9524
9514
|
}
|
|
9515
|
+
response = await this._client.fetch(postUrl, {
|
|
9516
|
+
headers,
|
|
9517
|
+
method: "POST",
|
|
9518
|
+
body: this._uploadStream,
|
|
9519
|
+
signal: this._controller.signal,
|
|
9520
|
+
// @ts-ignore
|
|
9521
|
+
duplex: "half"
|
|
9522
|
+
});
|
|
9525
9523
|
}
|
|
9526
|
-
mid++;
|
|
9527
|
-
}
|
|
9528
|
-
return frag;
|
|
9529
|
-
}
|
|
9530
|
-
static unquoteCredential(v) {
|
|
9531
|
-
if (!v) {
|
|
9532
|
-
return "";
|
|
9533
9524
|
}
|
|
9534
|
-
return
|
|
9525
|
+
return response;
|
|
9535
9526
|
}
|
|
9536
9527
|
};
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
super(getSession, client, (0, import_uuid.v4)().toString(), "liveIngress/whip", requestLogger);
|
|
9542
|
-
this._stream = stream;
|
|
9528
|
+
var LoadFromJob = class extends AbstractJob {
|
|
9529
|
+
constructor(location, params, getSession, client, requestLogger) {
|
|
9530
|
+
super(params, getSession, client, requestLogger);
|
|
9531
|
+
this._location = location;
|
|
9543
9532
|
}
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
const ingressUrl = this.gresUrl(session);
|
|
9547
|
-
const response = await this._client.fetch(ingressUrl, {
|
|
9548
|
-
headers: session.authenticationHeaders(),
|
|
9549
|
-
method: "GET"
|
|
9550
|
-
});
|
|
9551
|
-
if (response.status >= 300) {
|
|
9552
|
-
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9553
|
-
}
|
|
9554
|
-
return await this.onIceServers(response);
|
|
9533
|
+
get [Symbol.toStringTag]() {
|
|
9534
|
+
return "loadFromJob";
|
|
9555
9535
|
}
|
|
9556
|
-
async
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
return Promise.reject("fetching stream failed");
|
|
9536
|
+
async startJob() {
|
|
9537
|
+
const session = await this._getSession();
|
|
9538
|
+
if (!session.baseUrl) {
|
|
9539
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9561
9540
|
}
|
|
9541
|
+
const body = {
|
|
9542
|
+
sourceType: "URL",
|
|
9543
|
+
url: this._location,
|
|
9544
|
+
params: this._params
|
|
9545
|
+
};
|
|
9546
|
+
const headers = {
|
|
9547
|
+
...session.authenticationHeaders(),
|
|
9548
|
+
Accept: "application/jsonl",
|
|
9549
|
+
"Content-Type": "application/json"
|
|
9550
|
+
};
|
|
9551
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9552
|
+
return await this._client.fetch(patchUrl, {
|
|
9553
|
+
headers,
|
|
9554
|
+
method: "PATCH",
|
|
9555
|
+
body: JSON.stringify(body),
|
|
9556
|
+
signal: this._controller.signal,
|
|
9557
|
+
// @ts-ignore
|
|
9558
|
+
eyepop: { responseStreaming: true }
|
|
9559
|
+
});
|
|
9562
9560
|
}
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
if (this._queuedCandidates.length !== 0) {
|
|
9569
|
-
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9570
|
-
this._queuedCandidates = [];
|
|
9571
|
-
}
|
|
9572
|
-
return this;
|
|
9561
|
+
};
|
|
9562
|
+
var LoadFromAssetUuidJob = class extends AbstractJob {
|
|
9563
|
+
constructor(assetUuid, params, getSession, client, requestLogger) {
|
|
9564
|
+
super(params, getSession, client, requestLogger);
|
|
9565
|
+
this._assetUuid = assetUuid;
|
|
9573
9566
|
}
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
throw new Error("onIceServers no stream");
|
|
9577
|
-
}
|
|
9578
|
-
const stream = this._stream;
|
|
9579
|
-
const pc = new RTCPeerConnection({
|
|
9580
|
-
iceServers: WebrtcBase.linkToIceServers(response.headers.get("Link"))
|
|
9581
|
-
});
|
|
9582
|
-
this._pc = pc;
|
|
9583
|
-
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9584
|
-
return new Promise(async (resolve, reject) => {
|
|
9585
|
-
pc.oniceconnectionstatechange = () => {
|
|
9586
|
-
switch (pc.iceConnectionState) {
|
|
9587
|
-
case "failed":
|
|
9588
|
-
case "disconnected":
|
|
9589
|
-
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9590
|
-
break;
|
|
9591
|
-
case "connected":
|
|
9592
|
-
resolve(this);
|
|
9593
|
-
break;
|
|
9594
|
-
}
|
|
9595
|
-
};
|
|
9596
|
-
stream.getTracks().forEach((track) => {
|
|
9597
|
-
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9598
|
-
pc.addTrack(track, stream);
|
|
9599
|
-
});
|
|
9600
|
-
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9601
|
-
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9602
|
-
pc.addTrack(trackEvent.track, stream);
|
|
9603
|
-
});
|
|
9604
|
-
await this.onLocalOffer(await pc.createOffer());
|
|
9605
|
-
});
|
|
9567
|
+
get [Symbol.toStringTag]() {
|
|
9568
|
+
return "loadFromAssetUuidJob";
|
|
9606
9569
|
}
|
|
9607
|
-
async
|
|
9608
|
-
const
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
const tracks = stream.getTracks();
|
|
9612
|
-
tracks.forEach((track) => {
|
|
9613
|
-
track.stop();
|
|
9614
|
-
});
|
|
9570
|
+
async startJob() {
|
|
9571
|
+
const session = await this._getSession();
|
|
9572
|
+
if (!session.baseUrl) {
|
|
9573
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9615
9574
|
}
|
|
9616
|
-
|
|
9575
|
+
const body = {
|
|
9576
|
+
sourceType: "ASSET_UUID",
|
|
9577
|
+
assetUuid: this._assetUuid,
|
|
9578
|
+
params: this._params
|
|
9579
|
+
};
|
|
9580
|
+
const headers = {
|
|
9581
|
+
...session.authenticationHeaders(),
|
|
9582
|
+
Accept: "application/jsonl",
|
|
9583
|
+
"Content-Type": "application/json"
|
|
9584
|
+
};
|
|
9585
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9586
|
+
return await this._client.fetch(patchUrl, {
|
|
9587
|
+
headers,
|
|
9588
|
+
method: "PATCH",
|
|
9589
|
+
body: JSON.stringify(body),
|
|
9590
|
+
signal: this._controller.signal,
|
|
9591
|
+
// @ts-ignore
|
|
9592
|
+
eyepop: { responseStreaming: true }
|
|
9593
|
+
});
|
|
9617
9594
|
}
|
|
9618
9595
|
};
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
super(getSession, client, ingressId, "liveIngress/whep", requestLogger);
|
|
9624
|
-
this._stream = null;
|
|
9625
|
-
}
|
|
9626
|
-
async close() {
|
|
9627
|
-
const stream = this._stream;
|
|
9628
|
-
this._stream = null;
|
|
9629
|
-
if (stream) {
|
|
9630
|
-
const tracks = stream.getTracks();
|
|
9631
|
-
tracks.forEach((track) => {
|
|
9632
|
-
track.stop();
|
|
9633
|
-
});
|
|
9634
|
-
}
|
|
9635
|
-
return super.close();
|
|
9596
|
+
var LoadLiveIngressJob = class extends AbstractJob {
|
|
9597
|
+
constructor(ingressId, params, getSession, client, requestLogger) {
|
|
9598
|
+
super(params, getSession, client, requestLogger);
|
|
9599
|
+
this._ingressId = ingressId;
|
|
9636
9600
|
}
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
return Promise.resolve(this._stream);
|
|
9640
|
-
} else {
|
|
9641
|
-
return Promise.reject("fetching stream failed");
|
|
9642
|
-
}
|
|
9601
|
+
get [Symbol.toStringTag]() {
|
|
9602
|
+
return "loadLiveIngressJob";
|
|
9643
9603
|
}
|
|
9644
|
-
async
|
|
9604
|
+
async startJob() {
|
|
9645
9605
|
const session = await this._getSession();
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
headers: session.authenticationHeaders(),
|
|
9649
|
-
method: "GET"
|
|
9650
|
-
});
|
|
9651
|
-
if (response.status >= 300) {
|
|
9652
|
-
return Promise.reject(`unknown status code for GET '${egressUrl}': ${response.status} (${response.statusText})`);
|
|
9606
|
+
if (!session.baseUrl) {
|
|
9607
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9653
9608
|
}
|
|
9654
|
-
|
|
9609
|
+
const body = {
|
|
9610
|
+
sourceType: "LIVE_INGRESS",
|
|
9611
|
+
liveIngressId: this._ingressId,
|
|
9612
|
+
params: this._params
|
|
9613
|
+
};
|
|
9614
|
+
const headers = {
|
|
9615
|
+
...session.authenticationHeaders(),
|
|
9616
|
+
Accept: "application/jsonl",
|
|
9617
|
+
"Content-Type": "application/json"
|
|
9618
|
+
};
|
|
9619
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=preempt&processing=sync`;
|
|
9620
|
+
return await this._client.fetch(patchUrl, {
|
|
9621
|
+
headers,
|
|
9622
|
+
method: "PATCH",
|
|
9623
|
+
body: JSON.stringify(body),
|
|
9624
|
+
signal: this._controller.signal,
|
|
9625
|
+
// @ts-ignore
|
|
9626
|
+
eyepop: { responseStreaming: true }
|
|
9627
|
+
});
|
|
9655
9628
|
}
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
if (this._queuedCandidates.length !== 0) {
|
|
9662
|
-
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9663
|
-
this._queuedCandidates = [];
|
|
9664
|
-
}
|
|
9665
|
-
return this;
|
|
9629
|
+
};
|
|
9630
|
+
var LoadMediaStreamJob = class extends AbstractJob {
|
|
9631
|
+
constructor(mediaStream, params, getSession, client, requestLogger) {
|
|
9632
|
+
super(params, getSession, client, requestLogger);
|
|
9633
|
+
this._mediaStream = mediaStream;
|
|
9666
9634
|
}
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9635
|
+
get [Symbol.toStringTag]() {
|
|
9636
|
+
return "loadLiveIngressJob";
|
|
9637
|
+
}
|
|
9638
|
+
async startJob() {
|
|
9639
|
+
const session = await this._getSession();
|
|
9640
|
+
if (!session.baseUrl) {
|
|
9641
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9670
9642
|
}
|
|
9671
|
-
const
|
|
9672
|
-
|
|
9643
|
+
const whip = new WebrtcWhip(
|
|
9644
|
+
this._mediaStream,
|
|
9645
|
+
async () => {
|
|
9646
|
+
return session;
|
|
9647
|
+
},
|
|
9648
|
+
this._client,
|
|
9649
|
+
true,
|
|
9650
|
+
this._requestLogger
|
|
9651
|
+
);
|
|
9652
|
+
whip.start().then((value) => {
|
|
9653
|
+
this._requestLogger.debug("direct whip for ingressId=%s successful", whip.ingressId());
|
|
9654
|
+
}).catch((reason) => {
|
|
9655
|
+
this._controller.abort(reason);
|
|
9673
9656
|
});
|
|
9674
|
-
const
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
case "connected":
|
|
9693
|
-
this._requestLogger.debug("oniceconnectionstatechange connected");
|
|
9694
|
-
break;
|
|
9695
|
-
}
|
|
9696
|
-
};
|
|
9697
|
-
await this.onLocalOffer(await pc.createOffer());
|
|
9657
|
+
const body = {
|
|
9658
|
+
sourceType: "WHIP",
|
|
9659
|
+
whipIngressId: whip.ingressId(),
|
|
9660
|
+
params: this._params
|
|
9661
|
+
};
|
|
9662
|
+
const headers = {
|
|
9663
|
+
...session.authenticationHeaders(),
|
|
9664
|
+
Accept: "application/jsonl",
|
|
9665
|
+
"Content-Type": "application/json"
|
|
9666
|
+
};
|
|
9667
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=preempt&processing=sync`;
|
|
9668
|
+
return await this._client.fetch(patchUrl, {
|
|
9669
|
+
headers,
|
|
9670
|
+
method: "PATCH",
|
|
9671
|
+
body: JSON.stringify(body),
|
|
9672
|
+
signal: this._controller.signal,
|
|
9673
|
+
// @ts-ignore
|
|
9674
|
+
eyepop: { responseStreaming: true }
|
|
9698
9675
|
});
|
|
9699
9676
|
}
|
|
9700
9677
|
};
|
|
@@ -10208,8 +10185,6 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10208
10185
|
this._pipelineId = null;
|
|
10209
10186
|
this._popName = null;
|
|
10210
10187
|
this._pipeline = null;
|
|
10211
|
-
this._ingressEventHandler = null;
|
|
10212
|
-
this._ingressEventWs = null;
|
|
10213
10188
|
this._sandboxId = null;
|
|
10214
10189
|
const sessionAuth = options.auth;
|
|
10215
10190
|
if (sessionAuth !== void 0 && sessionAuth.session !== void 0) {
|
|
@@ -10235,7 +10210,7 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10235
10210
|
});
|
|
10236
10211
|
if (response?.status != 204) {
|
|
10237
10212
|
const message = await response?.text();
|
|
10238
|
-
this._logger.info(`
|
|
10213
|
+
this._logger.info(`stopping pipeline failed, status ${response?.status}: ${message}`);
|
|
10239
10214
|
}
|
|
10240
10215
|
}
|
|
10241
10216
|
if (this._sandboxId && this._baseUrl) {
|
|
@@ -10409,42 +10384,6 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10409
10384
|
popId() {
|
|
10410
10385
|
return this.options().popId || null;
|
|
10411
10386
|
}
|
|
10412
|
-
onIngressEvent(handler) {
|
|
10413
|
-
this._ingressEventHandler = handler;
|
|
10414
|
-
this.startIngressWs().then(() => {
|
|
10415
|
-
}).catch((reason) => {
|
|
10416
|
-
this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
|
|
10417
|
-
});
|
|
10418
|
-
return this;
|
|
10419
|
-
}
|
|
10420
|
-
async liveIngress(stream) {
|
|
10421
|
-
if (!this._baseUrl || !this._client) {
|
|
10422
|
-
return Promise.reject("endpoint not connected, use connect()");
|
|
10423
|
-
}
|
|
10424
|
-
const whip = new WebrtcWhip(
|
|
10425
|
-
stream,
|
|
10426
|
-
async () => {
|
|
10427
|
-
return this.session();
|
|
10428
|
-
},
|
|
10429
|
-
this._client,
|
|
10430
|
-
this._requestLogger
|
|
10431
|
-
);
|
|
10432
|
-
return whip.start();
|
|
10433
|
-
}
|
|
10434
|
-
async liveEgress(ingressId) {
|
|
10435
|
-
if (!this._baseUrl || !this._client) {
|
|
10436
|
-
return Promise.reject("endpoint not connected, use connect()");
|
|
10437
|
-
}
|
|
10438
|
-
const whep = new WebrtcWhep(
|
|
10439
|
-
ingressId,
|
|
10440
|
-
async () => {
|
|
10441
|
-
return this.session();
|
|
10442
|
-
},
|
|
10443
|
-
this._client,
|
|
10444
|
-
this._requestLogger
|
|
10445
|
-
);
|
|
10446
|
-
return whep.start();
|
|
10447
|
-
}
|
|
10448
10387
|
async process(source, params) {
|
|
10449
10388
|
if (source.file !== void 0) {
|
|
10450
10389
|
return this.uploadFile(source, params);
|
|
@@ -10454,45 +10393,14 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10454
10393
|
return this.uploadPath(source, params);
|
|
10455
10394
|
} else if (source.url !== void 0) {
|
|
10456
10395
|
return this.loadFrom(source, params);
|
|
10457
|
-
} else if (source.ingressId !== void 0) {
|
|
10458
|
-
return this.loadLiveIngress(source, params);
|
|
10459
10396
|
} else if (source.assetUuid !== void 0) {
|
|
10460
10397
|
return this.loadFromAssetUuid(source, params);
|
|
10398
|
+
} else if (source.mediaStream !== void 0) {
|
|
10399
|
+
return this.loadMediaStream(source, params);
|
|
10461
10400
|
} else {
|
|
10462
10401
|
return Promise.reject("unknown source type");
|
|
10463
10402
|
}
|
|
10464
10403
|
}
|
|
10465
|
-
async startIngressWs() {
|
|
10466
|
-
const client = this._client;
|
|
10467
|
-
if (this._ingressEventWs || !this._baseUrl || !client) {
|
|
10468
|
-
return;
|
|
10469
|
-
}
|
|
10470
|
-
try {
|
|
10471
|
-
const session = await this.session();
|
|
10472
|
-
let response = await this.fetchWithRetry(async () => {
|
|
10473
|
-
const headers = {
|
|
10474
|
-
...this._authenticationHeaders(session)
|
|
10475
|
-
};
|
|
10476
|
-
const getTokenUrl = `${session.baseUrl}/liveIngress/events/token`;
|
|
10477
|
-
return client.fetch(getTokenUrl, { headers });
|
|
10478
|
-
});
|
|
10479
|
-
if (response.status != 200) {
|
|
10480
|
-
const message = await response.text();
|
|
10481
|
-
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
10482
|
-
}
|
|
10483
|
-
const wsAuthToken = await response.json();
|
|
10484
|
-
const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
|
|
10485
|
-
this._ingressEventWs = new WebSocket(wsUrl);
|
|
10486
|
-
this._ingressEventWs.addEventListener("message", (event) => {
|
|
10487
|
-
const ingressEvent = JSON.parse(event.data);
|
|
10488
|
-
if (this._ingressEventHandler) {
|
|
10489
|
-
this._ingressEventHandler(ingressEvent);
|
|
10490
|
-
}
|
|
10491
|
-
});
|
|
10492
|
-
} finally {
|
|
10493
|
-
this.updateState();
|
|
10494
|
-
}
|
|
10495
|
-
}
|
|
10496
10404
|
async uploadFile(source, params) {
|
|
10497
10405
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10498
10406
|
return Promise.reject("endpoint not connected, use connect()");
|
|
@@ -10658,15 +10566,15 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10658
10566
|
throw e;
|
|
10659
10567
|
}
|
|
10660
10568
|
}
|
|
10661
|
-
async
|
|
10569
|
+
async loadMediaStream(source, params) {
|
|
10662
10570
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10663
10571
|
throw new Error("endpoint not connected, use connect()");
|
|
10664
10572
|
}
|
|
10665
10573
|
await this._limit.acquire();
|
|
10666
10574
|
try {
|
|
10667
10575
|
this.updateState();
|
|
10668
|
-
const job = new
|
|
10669
|
-
source.
|
|
10576
|
+
const job = new LoadMediaStreamJob(
|
|
10577
|
+
source.mediaStream,
|
|
10670
10578
|
params,
|
|
10671
10579
|
async () => {
|
|
10672
10580
|
return this.session();
|
|
@@ -10814,9 +10722,6 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10814
10722
|
}
|
|
10815
10723
|
}
|
|
10816
10724
|
}
|
|
10817
|
-
if (!this._ingressEventWs && this._ingressEventHandler) {
|
|
10818
|
-
await this.startIngressWs();
|
|
10819
|
-
}
|
|
10820
10725
|
this.updateState();
|
|
10821
10726
|
return Promise.resolve(this);
|
|
10822
10727
|
}
|
|
@@ -11725,6 +11630,88 @@ var DataEndpoint = class extends Endpoint {
|
|
|
11725
11630
|
}
|
|
11726
11631
|
};
|
|
11727
11632
|
|
|
11633
|
+
// worker/webrtc_whep.ts
|
|
11634
|
+
var WebrtcWhep = class extends WebrtcBase {
|
|
11635
|
+
constructor(ingressId, getSession, client, requestLogger) {
|
|
11636
|
+
super(getSession, client, ingressId, "liveIngress/whep", false, requestLogger);
|
|
11637
|
+
this._stream = null;
|
|
11638
|
+
}
|
|
11639
|
+
async close() {
|
|
11640
|
+
const stream = this._stream;
|
|
11641
|
+
this._stream = null;
|
|
11642
|
+
if (stream) {
|
|
11643
|
+
const tracks = stream.getTracks();
|
|
11644
|
+
tracks.forEach((track) => {
|
|
11645
|
+
track.stop();
|
|
11646
|
+
});
|
|
11647
|
+
}
|
|
11648
|
+
return super.close();
|
|
11649
|
+
}
|
|
11650
|
+
async stream() {
|
|
11651
|
+
if (this._stream) {
|
|
11652
|
+
return Promise.resolve(this._stream);
|
|
11653
|
+
} else {
|
|
11654
|
+
return Promise.reject("fetching stream failed");
|
|
11655
|
+
}
|
|
11656
|
+
}
|
|
11657
|
+
async start() {
|
|
11658
|
+
const session = await this._getSession();
|
|
11659
|
+
const egressUrl = this.gresUrl(session);
|
|
11660
|
+
const response = await this._client.fetch(egressUrl, {
|
|
11661
|
+
headers: session.authenticationHeaders(),
|
|
11662
|
+
method: "GET"
|
|
11663
|
+
});
|
|
11664
|
+
if (response.status >= 300) {
|
|
11665
|
+
return Promise.reject(`unknown status code for GET '${egressUrl}': ${response.status} (${response.statusText})`);
|
|
11666
|
+
}
|
|
11667
|
+
return this.onIceServers(response);
|
|
11668
|
+
}
|
|
11669
|
+
async onRemoteAnswer(answer) {
|
|
11670
|
+
if (!this._pc) {
|
|
11671
|
+
throw new Error("onLocalOffer no peer connection");
|
|
11672
|
+
}
|
|
11673
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
11674
|
+
if (this._queuedCandidates.length !== 0) {
|
|
11675
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
11676
|
+
this._queuedCandidates = [];
|
|
11677
|
+
}
|
|
11678
|
+
return this;
|
|
11679
|
+
}
|
|
11680
|
+
async onIceServers(response) {
|
|
11681
|
+
if (this._stream) {
|
|
11682
|
+
throw new Error("onIceServers has stream");
|
|
11683
|
+
}
|
|
11684
|
+
const pc = new RTCPeerConnection({
|
|
11685
|
+
iceServers: WebrtcBase.linkToIceServers(response.headers.get("Link"))
|
|
11686
|
+
});
|
|
11687
|
+
const direction = "sendrecv";
|
|
11688
|
+
pc.addTransceiver("video", { direction });
|
|
11689
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
11690
|
+
this._pc = pc;
|
|
11691
|
+
this._requestLogger.info(`onIceServers ${pc.iceConnectionState}`);
|
|
11692
|
+
return new Promise(async (resolve, reject) => {
|
|
11693
|
+
pc.ontrack = (evt) => {
|
|
11694
|
+
this._requestLogger.debug(`new track: ${evt.track.kind}`);
|
|
11695
|
+
this._stream = evt.streams[0];
|
|
11696
|
+
resolve(this);
|
|
11697
|
+
};
|
|
11698
|
+
pc.oniceconnectionstatechange = () => {
|
|
11699
|
+
switch (pc.iceConnectionState) {
|
|
11700
|
+
case "failed":
|
|
11701
|
+
case "disconnected":
|
|
11702
|
+
this._requestLogger.debug("oniceconnectionstatechange disconnected");
|
|
11703
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
11704
|
+
break;
|
|
11705
|
+
case "connected":
|
|
11706
|
+
this._requestLogger.debug("oniceconnectionstatechange connected");
|
|
11707
|
+
break;
|
|
11708
|
+
}
|
|
11709
|
+
};
|
|
11710
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
11711
|
+
});
|
|
11712
|
+
}
|
|
11713
|
+
};
|
|
11714
|
+
|
|
11728
11715
|
// index.ts
|
|
11729
11716
|
var readEnv = (env) => {
|
|
11730
11717
|
if (typeof process !== "undefined") {
|
|
@@ -11860,6 +11847,7 @@ var index_default = EyePop;
|
|
|
11860
11847
|
LoadFromAssetUuidJob,
|
|
11861
11848
|
LoadFromJob,
|
|
11862
11849
|
LoadLiveIngressJob,
|
|
11850
|
+
LoadMediaStreamJob,
|
|
11863
11851
|
ModelExportStatus,
|
|
11864
11852
|
ModelFormat,
|
|
11865
11853
|
ModelPrecisionType,
|