@eyepop.ai/eyepop 1.17.4 → 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 +17 -25
- package/dist/eyepop.index.d.ts +17 -25
- 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.mjs
CHANGED
|
@@ -8886,748 +8886,724 @@ var ContourType = /* @__PURE__ */ ((ContourType2) => {
|
|
|
8886
8886
|
return ContourType2;
|
|
8887
8887
|
})(ContourType || {});
|
|
8888
8888
|
|
|
8889
|
-
// worker/
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8889
|
+
// worker/webrtc_whip.ts
|
|
8890
|
+
import { v4 as uuidv4 } from "uuid";
|
|
8891
|
+
|
|
8892
|
+
// worker/webrtc_base.ts
|
|
8893
|
+
import path from "path";
|
|
8894
|
+
var WebrtcBase = class _WebrtcBase {
|
|
8895
|
+
constructor(getSession, client, ingressId, urlBasePath, is_pipeline_direct, requestLogger) {
|
|
8894
8896
|
this._getSession = getSession;
|
|
8895
|
-
this._params = params ?? null;
|
|
8896
8897
|
this._client = client;
|
|
8897
8898
|
this._requestLogger = requestLogger;
|
|
8899
|
+
this._ingressId = ingressId;
|
|
8900
|
+
this._urlPath = `${urlBasePath}/${this._ingressId}`;
|
|
8901
|
+
this._is_pipeline_direct = is_pipeline_direct;
|
|
8902
|
+
this._pc = null;
|
|
8903
|
+
this._eTag = "";
|
|
8904
|
+
this._location = null;
|
|
8905
|
+
this._queuedCandidates = [];
|
|
8906
|
+
this._offerData = null;
|
|
8898
8907
|
}
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8908
|
+
async close() {
|
|
8909
|
+
const pc = this._pc;
|
|
8910
|
+
this._pc = null;
|
|
8911
|
+
if (pc) {
|
|
8912
|
+
return pc.close();
|
|
8902
8913
|
}
|
|
8903
|
-
return Stream.iterFromReadableStream(this._responseStream, this._controller, async (event) => {
|
|
8904
|
-
return await this.onEvent(event);
|
|
8905
|
-
});
|
|
8906
8914
|
}
|
|
8907
|
-
|
|
8908
|
-
return
|
|
8915
|
+
ingressId() {
|
|
8916
|
+
return this._ingressId;
|
|
8909
8917
|
}
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8918
|
+
gresUrl(session, location = null) {
|
|
8919
|
+
let urlPath;
|
|
8920
|
+
if (this._is_pipeline_direct) {
|
|
8921
|
+
if (!session.pipelineId) {
|
|
8922
|
+
throw new Error("cannot connect with is_pipeline_direct=true but !session.pipelineId");
|
|
8923
|
+
}
|
|
8924
|
+
urlPath = path.join("pipelines", session.pipelineId, this._urlPath);
|
|
8925
|
+
} else {
|
|
8926
|
+
urlPath = this._urlPath;
|
|
8913
8927
|
}
|
|
8914
|
-
|
|
8928
|
+
if (location) {
|
|
8929
|
+
urlPath = path.join(urlPath, location);
|
|
8930
|
+
}
|
|
8931
|
+
let baseUrl;
|
|
8932
|
+
if (session.baseUrl?.endsWith("/")) {
|
|
8933
|
+
baseUrl = session.baseUrl;
|
|
8934
|
+
} else {
|
|
8935
|
+
baseUrl = session.baseUrl + "/";
|
|
8936
|
+
}
|
|
8937
|
+
return new URL(urlPath, baseUrl);
|
|
8915
8938
|
}
|
|
8916
|
-
|
|
8917
|
-
this.
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
} else {
|
|
8936
|
-
reject(`response ${response.status}: ${response.statusText}`);
|
|
8937
|
-
break;
|
|
8938
|
-
}
|
|
8939
|
-
} else if (response.status != 200) {
|
|
8940
|
-
reject(`upload error ${response.status}: ${await response.text()}`);
|
|
8941
|
-
break;
|
|
8942
|
-
} else if (response.body) {
|
|
8943
|
-
resolve(response.body);
|
|
8944
|
-
break;
|
|
8945
|
-
} else {
|
|
8946
|
-
const text = await response.text();
|
|
8947
|
-
if (text) {
|
|
8948
|
-
resolve(readableStreamFromString(text));
|
|
8949
|
-
break;
|
|
8950
|
-
} else {
|
|
8951
|
-
reject("response body is empty");
|
|
8952
|
-
break;
|
|
8953
|
-
}
|
|
8954
|
-
}
|
|
8955
|
-
} catch (error) {
|
|
8956
|
-
if (retries--) {
|
|
8957
|
-
this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
|
|
8958
|
-
status(404);
|
|
8959
|
-
} else {
|
|
8960
|
-
status(500);
|
|
8961
|
-
reject(error);
|
|
8962
|
-
break;
|
|
8963
|
-
}
|
|
8964
|
-
}
|
|
8965
|
-
}
|
|
8966
|
-
} catch (reason) {
|
|
8967
|
-
reject(reason);
|
|
8968
|
-
} finally {
|
|
8969
|
-
done();
|
|
8970
|
-
}
|
|
8939
|
+
async onLocalOffer(offer) {
|
|
8940
|
+
if (!this._pc) {
|
|
8941
|
+
throw new Error("onLocalOffer no peer connection");
|
|
8942
|
+
}
|
|
8943
|
+
if (!offer.sdp) {
|
|
8944
|
+
throw new Error("onLocalOffer no sdp");
|
|
8945
|
+
}
|
|
8946
|
+
this._offerData = _WebrtcBase.parseOffer(offer.sdp);
|
|
8947
|
+
await this._pc.setLocalDescription(offer);
|
|
8948
|
+
const session = await this._getSession();
|
|
8949
|
+
const ingressUrl = this.gresUrl(session);
|
|
8950
|
+
const headers = {
|
|
8951
|
+
...session.authenticationHeaders(),
|
|
8952
|
+
"Content-Type": "application/sdp"
|
|
8953
|
+
};
|
|
8954
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
8955
|
+
headers,
|
|
8956
|
+
method: "POST",
|
|
8957
|
+
body: offer.sdp
|
|
8971
8958
|
});
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
this.
|
|
8959
|
+
if (response.status >= 300) {
|
|
8960
|
+
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
8961
|
+
}
|
|
8962
|
+
this._eTag = response.headers.get("ETag") ?? "";
|
|
8963
|
+
this._location = response.headers.get("Location");
|
|
8964
|
+
return await this.onRemoteAnswer(new RTCSessionDescription({
|
|
8965
|
+
type: "answer",
|
|
8966
|
+
sdp: await response.text()
|
|
8967
|
+
}));
|
|
8976
8968
|
}
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8969
|
+
async sendLocalCandidates(candidates) {
|
|
8970
|
+
if (!this._offerData) {
|
|
8971
|
+
throw new Error("sendLocalCandidates no offerData");
|
|
8972
|
+
}
|
|
8973
|
+
const session = await this._getSession();
|
|
8974
|
+
const ingressUrl = this.gresUrl(session, this._location);
|
|
8975
|
+
const headers = {
|
|
8976
|
+
...session.authenticationHeaders(),
|
|
8977
|
+
"Content-Type": "application/trickle-ice-sdpfrag",
|
|
8978
|
+
"If-Match": this._eTag
|
|
8979
|
+
};
|
|
8980
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
8981
|
+
headers,
|
|
8982
|
+
method: "PATCH",
|
|
8983
|
+
body: _WebrtcBase.generateSdpFragment(this._offerData, candidates)
|
|
8984
|
+
});
|
|
8985
|
+
if (response.status >= 300) {
|
|
8986
|
+
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
8987
|
+
}
|
|
8988
|
+
return this;
|
|
8982
8989
|
}
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
+
async onLocalCandidate(evt) {
|
|
8991
|
+
if (evt.candidate !== null) {
|
|
8992
|
+
if (this._eTag === "") {
|
|
8993
|
+
this._queuedCandidates.push(evt.candidate);
|
|
8994
|
+
} else {
|
|
8995
|
+
await this.sendLocalCandidates([evt.candidate]);
|
|
8996
|
+
}
|
|
8997
|
+
}
|
|
8998
|
+
return this;
|
|
8990
8999
|
}
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
9000
|
+
static linkToIceServers(links) {
|
|
9001
|
+
const servers = links !== null ? links.split(", ").map((link) => {
|
|
9002
|
+
let m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
9003
|
+
if (!m) {
|
|
9004
|
+
m = link.match(/^(.+?); rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
8995
9005
|
}
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
return Promise.reject("session.baseUrl must not ne null");
|
|
9006
|
+
if (!m) {
|
|
9007
|
+
return null;
|
|
8999
9008
|
}
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9009
|
+
const iceServer = {
|
|
9010
|
+
urls: [m[1]],
|
|
9011
|
+
username: WebrtcWhip.unquoteCredential(m[3]),
|
|
9012
|
+
credential: WebrtcWhip.unquoteCredential(m[4])
|
|
9013
|
+
// credentialType: m[3]? "password" : undefined
|
|
9014
|
+
};
|
|
9015
|
+
return iceServer;
|
|
9016
|
+
}) : [];
|
|
9017
|
+
return servers.filter(function(el) {
|
|
9018
|
+
return el != null;
|
|
9019
|
+
});
|
|
9020
|
+
}
|
|
9021
|
+
static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
|
|
9022
|
+
const sections = answer.split("m=");
|
|
9023
|
+
for (let i = 0; i < sections.length; i++) {
|
|
9024
|
+
const section = sections[i];
|
|
9025
|
+
if (section.startsWith("video")) {
|
|
9026
|
+
sections[i] = WebrtcWhip.setVideoBitrate(WebrtcWhip.setCodec(section, videoCodec), videoBitrate);
|
|
9027
|
+
} else if (section.startsWith("audio")) {
|
|
9028
|
+
sections[i] = WebrtcWhip.setAudioBitrate(WebrtcWhip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9029
|
+
}
|
|
9030
|
+
}
|
|
9031
|
+
return sections.join("m=");
|
|
9032
|
+
}
|
|
9033
|
+
static setCodec(section, codec) {
|
|
9034
|
+
const lines = section.split("\r\n");
|
|
9035
|
+
const lines2 = [];
|
|
9036
|
+
const payloadFormats = [];
|
|
9037
|
+
for (const line of lines) {
|
|
9038
|
+
if (!line.startsWith("a=rtpmap:")) {
|
|
9039
|
+
lines2.push(line);
|
|
9023
9040
|
} else {
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
"Content-Type": this._mimeType
|
|
9028
|
-
};
|
|
9029
|
-
if (this._size) {
|
|
9030
|
-
headers["Content-Length"] = `${this._size}`;
|
|
9041
|
+
if (codec && line.toLowerCase().includes(codec)) {
|
|
9042
|
+
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9043
|
+
lines2.push(line);
|
|
9031
9044
|
}
|
|
9032
|
-
request = this._client.fetch(postUrl, {
|
|
9033
|
-
headers,
|
|
9034
|
-
method: "POST",
|
|
9035
|
-
body: this._uploadStream,
|
|
9036
|
-
signal: this._controller.signal,
|
|
9037
|
-
// @ts-ignore
|
|
9038
|
-
duplex: "half",
|
|
9039
|
-
eyepop: { responseStreaming: true }
|
|
9040
|
-
});
|
|
9041
9045
|
}
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9046
|
+
}
|
|
9047
|
+
const lines3 = [];
|
|
9048
|
+
for (const line of lines2) {
|
|
9049
|
+
if (line.startsWith("a=fmtp:")) {
|
|
9050
|
+
if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
|
|
9051
|
+
lines3.push(line);
|
|
9045
9052
|
}
|
|
9046
|
-
}
|
|
9047
|
-
|
|
9048
|
-
|
|
9053
|
+
} else if (line.startsWith("a=rtcp-fb:")) {
|
|
9054
|
+
if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
|
|
9055
|
+
lines3.push(line);
|
|
9056
|
+
}
|
|
9057
|
+
} else {
|
|
9058
|
+
lines3.push(line);
|
|
9059
|
+
}
|
|
9049
9060
|
}
|
|
9050
|
-
return
|
|
9061
|
+
return lines3.join("\r\n");
|
|
9051
9062
|
}
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9063
|
+
static setVideoBitrate(section, bitrate) {
|
|
9064
|
+
let lines = section.split("\r\n");
|
|
9065
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9066
|
+
if (lines[i].startsWith("c=")) {
|
|
9067
|
+
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9068
|
+
break;
|
|
9069
|
+
}
|
|
9056
9070
|
}
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
const paramBlob = new Blob([params], { type: "application/json" });
|
|
9078
|
-
const formData = new FormData();
|
|
9079
|
-
const fileBlob = await new Response(this._uploadStream).blob();
|
|
9080
|
-
formData.append("params", paramBlob);
|
|
9081
|
-
formData.append("file", fileBlob);
|
|
9082
|
-
const headers = {
|
|
9083
|
-
...session.authenticationHeaders(),
|
|
9084
|
-
Accept: "application/jsonl"
|
|
9085
|
-
};
|
|
9086
|
-
response = await this._client.fetch(postUrl, {
|
|
9087
|
-
headers,
|
|
9088
|
-
method: "POST",
|
|
9089
|
-
body: formData,
|
|
9090
|
-
signal: this._controller.signal,
|
|
9091
|
-
// @ts-ignore
|
|
9092
|
-
duplex: "half",
|
|
9093
|
-
eyepop: { responseStreaming: true }
|
|
9094
|
-
});
|
|
9095
|
-
} else {
|
|
9096
|
-
const headers = {
|
|
9097
|
-
...session.authenticationHeaders(),
|
|
9098
|
-
Accept: "application/jsonl",
|
|
9099
|
-
"Content-Type": this._mimeType
|
|
9100
|
-
};
|
|
9101
|
-
if (this._size) {
|
|
9102
|
-
headers["Content-Length"] = `${this._size}`;
|
|
9071
|
+
return lines.join("\r\n");
|
|
9072
|
+
}
|
|
9073
|
+
static setAudioBitrate(section, bitrate, voice) {
|
|
9074
|
+
let opusPayloadFormat = "";
|
|
9075
|
+
let lines = section.split("\r\n");
|
|
9076
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9077
|
+
if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
|
|
9078
|
+
opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
|
|
9079
|
+
break;
|
|
9080
|
+
}
|
|
9081
|
+
}
|
|
9082
|
+
if (opusPayloadFormat === "") {
|
|
9083
|
+
return section;
|
|
9084
|
+
}
|
|
9085
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9086
|
+
if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
|
|
9087
|
+
if (voice) {
|
|
9088
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
|
|
9089
|
+
} else {
|
|
9090
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
|
|
9103
9091
|
}
|
|
9104
|
-
response = await this._client.fetch(postUrl, {
|
|
9105
|
-
headers,
|
|
9106
|
-
method: "POST",
|
|
9107
|
-
body: this._uploadStream,
|
|
9108
|
-
signal: this._controller.signal,
|
|
9109
|
-
// @ts-ignore
|
|
9110
|
-
duplex: "half"
|
|
9111
|
-
});
|
|
9112
9092
|
}
|
|
9113
9093
|
}
|
|
9114
|
-
return
|
|
9115
|
-
}
|
|
9116
|
-
};
|
|
9117
|
-
var LoadFromJob = class extends AbstractJob {
|
|
9118
|
-
constructor(location, params, getSession, client, requestLogger) {
|
|
9119
|
-
super(params, getSession, client, requestLogger);
|
|
9120
|
-
this._location = location;
|
|
9121
|
-
}
|
|
9122
|
-
get [Symbol.toStringTag]() {
|
|
9123
|
-
return "loadFromJob";
|
|
9094
|
+
return lines.join("\r\n");
|
|
9124
9095
|
}
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9096
|
+
static parseOffer(offer) {
|
|
9097
|
+
let medias = [];
|
|
9098
|
+
let iceUfrag = "";
|
|
9099
|
+
let icePwd = "";
|
|
9100
|
+
for (const line of offer.split("\r\n")) {
|
|
9101
|
+
if (line.startsWith("m=")) {
|
|
9102
|
+
medias.push(line.slice("m=".length));
|
|
9103
|
+
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9104
|
+
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9105
|
+
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9106
|
+
icePwd = line.slice("a=ice-pwd:".length);
|
|
9107
|
+
}
|
|
9129
9108
|
}
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
};
|
|
9135
|
-
const headers = {
|
|
9136
|
-
...session.authenticationHeaders(),
|
|
9137
|
-
Accept: "application/jsonl",
|
|
9138
|
-
"Content-Type": "application/json"
|
|
9109
|
+
return {
|
|
9110
|
+
iceUfrag,
|
|
9111
|
+
icePwd,
|
|
9112
|
+
medias
|
|
9139
9113
|
};
|
|
9140
|
-
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9141
|
-
return await this._client.fetch(patchUrl, {
|
|
9142
|
-
headers,
|
|
9143
|
-
method: "PATCH",
|
|
9144
|
-
body: JSON.stringify(body),
|
|
9145
|
-
signal: this._controller.signal,
|
|
9146
|
-
// @ts-ignore
|
|
9147
|
-
eyepop: { responseStreaming: true }
|
|
9148
|
-
});
|
|
9149
|
-
}
|
|
9150
|
-
};
|
|
9151
|
-
var LoadFromAssetUuidJob = class extends AbstractJob {
|
|
9152
|
-
constructor(assetUuid, params, getSession, client, requestLogger) {
|
|
9153
|
-
super(params, getSession, client, requestLogger);
|
|
9154
|
-
this._assetUuid = assetUuid;
|
|
9155
9114
|
}
|
|
9156
|
-
|
|
9157
|
-
|
|
9115
|
+
static generateSdpFragment(offerData, candidates) {
|
|
9116
|
+
const candidatesByMedia = /* @__PURE__ */ new Map();
|
|
9117
|
+
for (const candidate of candidates) {
|
|
9118
|
+
if (candidate.sdpMLineIndex !== null) {
|
|
9119
|
+
const mid2 = candidate.sdpMLineIndex;
|
|
9120
|
+
let matched = candidatesByMedia.get(mid2);
|
|
9121
|
+
if (matched === void 0) {
|
|
9122
|
+
matched = [];
|
|
9123
|
+
candidatesByMedia.set(mid2, matched);
|
|
9124
|
+
}
|
|
9125
|
+
matched.push(candidate);
|
|
9126
|
+
}
|
|
9127
|
+
}
|
|
9128
|
+
let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
|
|
9129
|
+
let mid = 0;
|
|
9130
|
+
for (const media of offerData.medias) {
|
|
9131
|
+
let matched = candidatesByMedia.get(mid);
|
|
9132
|
+
if (matched !== void 0) {
|
|
9133
|
+
frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
|
|
9134
|
+
for (const candidate of matched) {
|
|
9135
|
+
frag += "a=" + candidate.candidate + "\r\n";
|
|
9136
|
+
}
|
|
9137
|
+
}
|
|
9138
|
+
mid++;
|
|
9139
|
+
}
|
|
9140
|
+
return frag;
|
|
9158
9141
|
}
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
return Promise.reject("session.baseUrl must not ne null");
|
|
9142
|
+
static unquoteCredential(v) {
|
|
9143
|
+
if (!v) {
|
|
9144
|
+
return "";
|
|
9163
9145
|
}
|
|
9164
|
-
|
|
9165
|
-
sourceType: "ASSET_UUID",
|
|
9166
|
-
assetUuid: this._assetUuid,
|
|
9167
|
-
params: this._params
|
|
9168
|
-
};
|
|
9169
|
-
const headers = {
|
|
9170
|
-
...session.authenticationHeaders(),
|
|
9171
|
-
Accept: "application/jsonl",
|
|
9172
|
-
"Content-Type": "application/json"
|
|
9173
|
-
};
|
|
9174
|
-
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9175
|
-
return await this._client.fetch(patchUrl, {
|
|
9176
|
-
headers,
|
|
9177
|
-
method: "PATCH",
|
|
9178
|
-
body: JSON.stringify(body),
|
|
9179
|
-
signal: this._controller.signal,
|
|
9180
|
-
// @ts-ignore
|
|
9181
|
-
eyepop: { responseStreaming: true }
|
|
9182
|
-
});
|
|
9146
|
+
return JSON.parse(`"${v}"`);
|
|
9183
9147
|
}
|
|
9184
9148
|
};
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
return "loadLiveIngressJob";
|
|
9149
|
+
|
|
9150
|
+
// worker/webrtc_whip.ts
|
|
9151
|
+
var WebrtcWhip = class extends WebrtcBase {
|
|
9152
|
+
constructor(stream, getSession, client, is_pipeline_direct, requestLogger) {
|
|
9153
|
+
super(getSession, client, uuidv4().toString(), "liveIngress/whip", is_pipeline_direct, requestLogger);
|
|
9154
|
+
this._stream = stream;
|
|
9192
9155
|
}
|
|
9193
|
-
async
|
|
9156
|
+
async start() {
|
|
9194
9157
|
const session = await this._getSession();
|
|
9195
|
-
|
|
9196
|
-
|
|
9158
|
+
const ingressUrl = this.gresUrl(session);
|
|
9159
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9160
|
+
headers: session.authenticationHeaders(),
|
|
9161
|
+
method: "GET"
|
|
9162
|
+
});
|
|
9163
|
+
if (response.status >= 300) {
|
|
9164
|
+
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9197
9165
|
}
|
|
9198
|
-
|
|
9199
|
-
sourceType: "LIVE_INGRESS",
|
|
9200
|
-
liveIngressId: this._ingressId,
|
|
9201
|
-
params: this._params
|
|
9202
|
-
};
|
|
9203
|
-
const headers = {
|
|
9204
|
-
...session.authenticationHeaders(),
|
|
9205
|
-
Accept: "application/jsonl",
|
|
9206
|
-
"Content-Type": "application/json"
|
|
9207
|
-
};
|
|
9208
|
-
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=preempt&processing=sync`;
|
|
9209
|
-
return await this._client.fetch(patchUrl, {
|
|
9210
|
-
headers,
|
|
9211
|
-
method: "PATCH",
|
|
9212
|
-
body: JSON.stringify(body),
|
|
9213
|
-
signal: this._controller.signal,
|
|
9214
|
-
// @ts-ignore
|
|
9215
|
-
eyepop: { responseStreaming: true }
|
|
9216
|
-
});
|
|
9217
|
-
}
|
|
9218
|
-
};
|
|
9219
|
-
|
|
9220
|
-
// worker/webrtc_whip.ts
|
|
9221
|
-
import { v4 as uuidv4 } from "uuid";
|
|
9222
|
-
|
|
9223
|
-
// worker/webrtc_base.ts
|
|
9224
|
-
import path from "path";
|
|
9225
|
-
var WebrtcBase = class _WebrtcBase {
|
|
9226
|
-
constructor(getSession, client, ingressId, urlBasePath, requestLogger) {
|
|
9227
|
-
this._getSession = getSession;
|
|
9228
|
-
this._client = client;
|
|
9229
|
-
this._requestLogger = requestLogger;
|
|
9230
|
-
this._ingressId = ingressId;
|
|
9231
|
-
this._urlPath = `${urlBasePath}/${this._ingressId}`;
|
|
9232
|
-
this._pc = null;
|
|
9233
|
-
this._eTag = "";
|
|
9234
|
-
this._location = null;
|
|
9235
|
-
this._queuedCandidates = [];
|
|
9236
|
-
this._offerData = null;
|
|
9237
|
-
}
|
|
9238
|
-
async close() {
|
|
9239
|
-
const pc = this._pc;
|
|
9240
|
-
this._pc = null;
|
|
9241
|
-
if (pc) {
|
|
9242
|
-
return pc.close();
|
|
9243
|
-
}
|
|
9244
|
-
}
|
|
9245
|
-
ingressId() {
|
|
9246
|
-
return this._ingressId;
|
|
9166
|
+
return await this.onIceServers(response);
|
|
9247
9167
|
}
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
urlPath = path.join(this._urlPath, location);
|
|
9252
|
-
} else {
|
|
9253
|
-
urlPath = this._urlPath;
|
|
9254
|
-
}
|
|
9255
|
-
let baseUrl;
|
|
9256
|
-
if (session.baseUrl?.endsWith("/")) {
|
|
9257
|
-
baseUrl = session.baseUrl;
|
|
9168
|
+
async stream() {
|
|
9169
|
+
if (this._stream) {
|
|
9170
|
+
return Promise.resolve(this._stream);
|
|
9258
9171
|
} else {
|
|
9259
|
-
|
|
9172
|
+
return Promise.reject("fetching stream failed");
|
|
9260
9173
|
}
|
|
9261
|
-
return new URL(urlPath, baseUrl);
|
|
9262
9174
|
}
|
|
9263
|
-
async
|
|
9175
|
+
async onRemoteAnswer(answer) {
|
|
9264
9176
|
if (!this._pc) {
|
|
9265
9177
|
throw new Error("onLocalOffer no peer connection");
|
|
9266
9178
|
}
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
await this._pc.setLocalDescription(offer);
|
|
9272
|
-
const session = await this._getSession();
|
|
9273
|
-
const ingressUrl = this.gresUrl(session);
|
|
9274
|
-
const headers = {
|
|
9275
|
-
...session.authenticationHeaders(),
|
|
9276
|
-
"Content-Type": "application/sdp"
|
|
9277
|
-
};
|
|
9278
|
-
const response = await this._client.fetch(ingressUrl, {
|
|
9279
|
-
headers,
|
|
9280
|
-
method: "POST",
|
|
9281
|
-
body: offer.sdp
|
|
9282
|
-
});
|
|
9283
|
-
if (response.status != 201) {
|
|
9284
|
-
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9179
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
9180
|
+
if (this._queuedCandidates.length !== 0) {
|
|
9181
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9182
|
+
this._queuedCandidates = [];
|
|
9285
9183
|
}
|
|
9286
|
-
this
|
|
9287
|
-
this._location = response.headers.get("Location");
|
|
9288
|
-
return await this.onRemoteAnswer(new RTCSessionDescription({
|
|
9289
|
-
type: "answer",
|
|
9290
|
-
sdp: await response.text()
|
|
9291
|
-
}));
|
|
9184
|
+
return this;
|
|
9292
9185
|
}
|
|
9293
|
-
async
|
|
9294
|
-
if (!this.
|
|
9295
|
-
throw new Error("
|
|
9186
|
+
async onIceServers(response) {
|
|
9187
|
+
if (!this._stream) {
|
|
9188
|
+
throw new Error("onIceServers no stream");
|
|
9296
9189
|
}
|
|
9297
|
-
const
|
|
9298
|
-
const
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9190
|
+
const stream = this._stream;
|
|
9191
|
+
const pc = new RTCPeerConnection({
|
|
9192
|
+
iceServers: WebrtcBase.linkToIceServers(response.headers.get("Link"))
|
|
9193
|
+
});
|
|
9194
|
+
this._pc = pc;
|
|
9195
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9196
|
+
return new Promise(async (resolve, reject) => {
|
|
9197
|
+
pc.oniceconnectionstatechange = () => {
|
|
9198
|
+
switch (pc.iceConnectionState) {
|
|
9199
|
+
case "failed":
|
|
9200
|
+
case "disconnected":
|
|
9201
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9202
|
+
break;
|
|
9203
|
+
case "connected":
|
|
9204
|
+
resolve(this);
|
|
9205
|
+
break;
|
|
9206
|
+
}
|
|
9207
|
+
};
|
|
9208
|
+
stream.getTracks().forEach((track) => {
|
|
9209
|
+
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9210
|
+
pc.addTrack(track, stream);
|
|
9211
|
+
});
|
|
9212
|
+
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9213
|
+
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9214
|
+
pc.addTrack(trackEvent.track, stream);
|
|
9215
|
+
});
|
|
9216
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
9308
9217
|
});
|
|
9309
|
-
if (response.status != 204) {
|
|
9310
|
-
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9311
|
-
}
|
|
9312
|
-
return this;
|
|
9313
9218
|
}
|
|
9314
|
-
async
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9219
|
+
async close() {
|
|
9220
|
+
const stream = this._stream;
|
|
9221
|
+
this._stream = null;
|
|
9222
|
+
if (stream) {
|
|
9223
|
+
const tracks = stream.getTracks();
|
|
9224
|
+
tracks.forEach((track) => {
|
|
9225
|
+
track.stop();
|
|
9226
|
+
});
|
|
9321
9227
|
}
|
|
9322
|
-
return
|
|
9228
|
+
return super.close();
|
|
9323
9229
|
}
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
};
|
|
9336
|
-
return iceServer;
|
|
9337
|
-
}) : [];
|
|
9338
|
-
return servers.filter(function(el) {
|
|
9339
|
-
return el != null;
|
|
9340
|
-
});
|
|
9230
|
+
};
|
|
9231
|
+
|
|
9232
|
+
// worker/jobs.ts
|
|
9233
|
+
var AbstractJob = class {
|
|
9234
|
+
constructor(params, getSession, client, requestLogger) {
|
|
9235
|
+
this._responseStream = null;
|
|
9236
|
+
this._controller = new AbortController();
|
|
9237
|
+
this._getSession = getSession;
|
|
9238
|
+
this._params = params ?? null;
|
|
9239
|
+
this._client = client;
|
|
9240
|
+
this._requestLogger = requestLogger;
|
|
9341
9241
|
}
|
|
9342
|
-
|
|
9343
|
-
|
|
9344
|
-
|
|
9345
|
-
const section = sections[i];
|
|
9346
|
-
if (section.startsWith("video")) {
|
|
9347
|
-
sections[i] = WebrtcWhip.setVideoBitrate(WebrtcWhip.setCodec(section, videoCodec), videoBitrate);
|
|
9348
|
-
} else if (section.startsWith("audio")) {
|
|
9349
|
-
sections[i] = WebrtcWhip.setAudioBitrate(WebrtcWhip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9350
|
-
}
|
|
9242
|
+
[Symbol.asyncIterator]() {
|
|
9243
|
+
if (!this._responseStream) {
|
|
9244
|
+
throw Error("logical bug");
|
|
9351
9245
|
}
|
|
9352
|
-
return
|
|
9246
|
+
return Stream.iterFromReadableStream(this._responseStream, this._controller, async (event) => {
|
|
9247
|
+
return await this.onEvent(event);
|
|
9248
|
+
});
|
|
9353
9249
|
}
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
lines2.push(line);
|
|
9361
|
-
} else {
|
|
9362
|
-
if (codec && line.toLowerCase().includes(codec)) {
|
|
9363
|
-
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9364
|
-
lines2.push(line);
|
|
9365
|
-
}
|
|
9366
|
-
}
|
|
9250
|
+
async startJob() {
|
|
9251
|
+
return Promise.reject("abstract class");
|
|
9252
|
+
}
|
|
9253
|
+
async onEvent(event) {
|
|
9254
|
+
if (event.type == "error") {
|
|
9255
|
+
return Promise.reject(`Error event for source ${event.source_id}: ${event.message}`);
|
|
9367
9256
|
}
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9257
|
+
return Promise.resolve();
|
|
9258
|
+
}
|
|
9259
|
+
start(done, status) {
|
|
9260
|
+
this._responseStream = new Promise(async (resolve, reject) => {
|
|
9261
|
+
try {
|
|
9262
|
+
let retries = 1;
|
|
9263
|
+
while (true) {
|
|
9264
|
+
try {
|
|
9265
|
+
const response = await this.startJob();
|
|
9266
|
+
if (response.status == 401) {
|
|
9267
|
+
status(response.status);
|
|
9268
|
+
if (retries--) {
|
|
9269
|
+
this._requestLogger.info("received 401 response, attempt to reauthorize once");
|
|
9270
|
+
} else {
|
|
9271
|
+
reject(`response ${response.status}: ${response.statusText}`);
|
|
9272
|
+
break;
|
|
9273
|
+
}
|
|
9274
|
+
} else if (response.status == 404) {
|
|
9275
|
+
status(response.status);
|
|
9276
|
+
if (retries--) {
|
|
9277
|
+
this._requestLogger.info("received 404 response, attempt to restart pop");
|
|
9278
|
+
} else {
|
|
9279
|
+
reject(`response ${response.status}: ${response.statusText}`);
|
|
9280
|
+
break;
|
|
9281
|
+
}
|
|
9282
|
+
} else if (response.status != 200) {
|
|
9283
|
+
reject(`upload error ${response.status}: ${await response.text()}`);
|
|
9284
|
+
break;
|
|
9285
|
+
} else if (response.body) {
|
|
9286
|
+
resolve(response.body);
|
|
9287
|
+
break;
|
|
9288
|
+
} else {
|
|
9289
|
+
const text = await response.text();
|
|
9290
|
+
if (text) {
|
|
9291
|
+
resolve(readableStreamFromString(text));
|
|
9292
|
+
break;
|
|
9293
|
+
} else {
|
|
9294
|
+
reject("response body is empty");
|
|
9295
|
+
break;
|
|
9296
|
+
}
|
|
9297
|
+
}
|
|
9298
|
+
} catch (error) {
|
|
9299
|
+
if (retries--) {
|
|
9300
|
+
this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
|
|
9301
|
+
status(404);
|
|
9302
|
+
} else {
|
|
9303
|
+
status(500);
|
|
9304
|
+
reject(error);
|
|
9305
|
+
break;
|
|
9306
|
+
}
|
|
9307
|
+
}
|
|
9377
9308
|
}
|
|
9378
|
-
}
|
|
9379
|
-
|
|
9309
|
+
} catch (reason) {
|
|
9310
|
+
reject(reason);
|
|
9311
|
+
} finally {
|
|
9312
|
+
done();
|
|
9380
9313
|
}
|
|
9381
|
-
}
|
|
9382
|
-
return
|
|
9314
|
+
});
|
|
9315
|
+
return this;
|
|
9383
9316
|
}
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
for (let i = 0; i < lines.length; i++) {
|
|
9387
|
-
if (lines[i].startsWith("c=")) {
|
|
9388
|
-
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9389
|
-
break;
|
|
9390
|
-
}
|
|
9391
|
-
}
|
|
9392
|
-
return lines.join("\r\n");
|
|
9317
|
+
cancel() {
|
|
9318
|
+
this._controller.abort("cancelled");
|
|
9393
9319
|
}
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9320
|
+
};
|
|
9321
|
+
AbstractJob.n = 0;
|
|
9322
|
+
var UploadJob = class extends AbstractJob {
|
|
9323
|
+
get [Symbol.toStringTag]() {
|
|
9324
|
+
return "uploadJob";
|
|
9325
|
+
}
|
|
9326
|
+
constructor(stream, mimeType, size, videoMode, params, getSession, client, requestLogger) {
|
|
9327
|
+
super(params, getSession, client, requestLogger);
|
|
9328
|
+
this._uploadStream = stream;
|
|
9329
|
+
this._mimeType = mimeType;
|
|
9330
|
+
this._size = size;
|
|
9331
|
+
this._videoMode = videoMode;
|
|
9332
|
+
this._needsFullDuplex = !client.isFullDuplex() && mimeType.startsWith("video/") && videoMode == "stream" /* STREAM */;
|
|
9333
|
+
}
|
|
9334
|
+
async onEvent(event) {
|
|
9335
|
+
if (event.type == "prepared") {
|
|
9336
|
+
if (!event.source_id) {
|
|
9337
|
+
return Promise.reject("did not get a prepared sourceId to simulate full duplex");
|
|
9401
9338
|
}
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9339
|
+
const session = await this._getSession();
|
|
9340
|
+
if (!session.baseUrl) {
|
|
9341
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9342
|
+
}
|
|
9343
|
+
let request;
|
|
9344
|
+
const videoModeQuery = this._videoMode ? `&videoMode=${this._videoMode}` : "";
|
|
9345
|
+
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=async&sourceId=${event.source_id}${videoModeQuery}`;
|
|
9346
|
+
if (this._params) {
|
|
9347
|
+
const params = JSON.stringify(this._params);
|
|
9348
|
+
const paramBlob = new Blob([params], { type: "application/json" });
|
|
9349
|
+
const formData = new FormData();
|
|
9350
|
+
const fileBlob = await new Response(this._uploadStream).blob();
|
|
9351
|
+
formData.append("params", paramBlob);
|
|
9352
|
+
formData.append("file", fileBlob);
|
|
9353
|
+
const headers = {
|
|
9354
|
+
...session.authenticationHeaders(),
|
|
9355
|
+
Accept: "application/jsonl"
|
|
9356
|
+
};
|
|
9357
|
+
request = this._client.fetch(postUrl, {
|
|
9358
|
+
headers,
|
|
9359
|
+
method: "POST",
|
|
9360
|
+
body: formData,
|
|
9361
|
+
signal: this._controller.signal,
|
|
9362
|
+
// @ts-ignore
|
|
9363
|
+
duplex: "half",
|
|
9364
|
+
eyepop: { responseStreaming: true }
|
|
9365
|
+
});
|
|
9366
|
+
} else {
|
|
9367
|
+
const headers = {
|
|
9368
|
+
...session.authenticationHeaders(),
|
|
9369
|
+
Accept: "application/jsonl",
|
|
9370
|
+
"Content-Type": this._mimeType
|
|
9371
|
+
};
|
|
9372
|
+
if (this._size) {
|
|
9373
|
+
headers["Content-Length"] = `${this._size}`;
|
|
9412
9374
|
}
|
|
9375
|
+
request = this._client.fetch(postUrl, {
|
|
9376
|
+
headers,
|
|
9377
|
+
method: "POST",
|
|
9378
|
+
body: this._uploadStream,
|
|
9379
|
+
signal: this._controller.signal,
|
|
9380
|
+
// @ts-ignore
|
|
9381
|
+
duplex: "half",
|
|
9382
|
+
eyepop: { responseStreaming: true }
|
|
9383
|
+
});
|
|
9413
9384
|
}
|
|
9385
|
+
request.then(async (value) => {
|
|
9386
|
+
if (value.status != 204) {
|
|
9387
|
+
this._requestLogger.debug(`unexpected status ${value.status} (${await value.text()}) for POST ${postUrl}`);
|
|
9388
|
+
}
|
|
9389
|
+
}).catch((reason) => {
|
|
9390
|
+
this._requestLogger.debug(`error ${reason} for POST ${postUrl}`);
|
|
9391
|
+
});
|
|
9414
9392
|
}
|
|
9415
|
-
return
|
|
9416
|
-
}
|
|
9417
|
-
static parseOffer(offer) {
|
|
9418
|
-
let medias = [];
|
|
9419
|
-
let iceUfrag = "";
|
|
9420
|
-
let icePwd = "";
|
|
9421
|
-
for (const line of offer.split("\r\n")) {
|
|
9422
|
-
if (line.startsWith("m=")) {
|
|
9423
|
-
medias.push(line.slice("m=".length));
|
|
9424
|
-
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9425
|
-
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9426
|
-
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9427
|
-
icePwd = line.slice("a=ice-pwd:".length);
|
|
9428
|
-
}
|
|
9429
|
-
}
|
|
9430
|
-
return {
|
|
9431
|
-
iceUfrag,
|
|
9432
|
-
icePwd,
|
|
9433
|
-
medias
|
|
9434
|
-
};
|
|
9393
|
+
return Promise.resolve();
|
|
9435
9394
|
}
|
|
9436
|
-
|
|
9437
|
-
const
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
const mid2 = candidate.sdpMLineIndex;
|
|
9441
|
-
let matched = candidatesByMedia.get(mid2);
|
|
9442
|
-
if (matched === void 0) {
|
|
9443
|
-
matched = [];
|
|
9444
|
-
candidatesByMedia.set(mid2, matched);
|
|
9445
|
-
}
|
|
9446
|
-
matched.push(candidate);
|
|
9447
|
-
}
|
|
9395
|
+
async startJob() {
|
|
9396
|
+
const session = await this._getSession();
|
|
9397
|
+
if (!session.baseUrl) {
|
|
9398
|
+
return Promise.reject("session.baseUrl must not be null");
|
|
9448
9399
|
}
|
|
9449
|
-
let
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9400
|
+
let response;
|
|
9401
|
+
if (this._needsFullDuplex) {
|
|
9402
|
+
const prepareUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/prepareSource?timeout=10s`;
|
|
9403
|
+
const headers = {
|
|
9404
|
+
...session.authenticationHeaders(),
|
|
9405
|
+
Accept: "application/jsonl"
|
|
9406
|
+
};
|
|
9407
|
+
response = await this._client.fetch(prepareUrl, {
|
|
9408
|
+
headers,
|
|
9409
|
+
method: "POST",
|
|
9410
|
+
signal: this._controller.signal,
|
|
9411
|
+
// @ts-ignore
|
|
9412
|
+
duplex: "half",
|
|
9413
|
+
eyepop: { responseStreaming: true }
|
|
9414
|
+
});
|
|
9415
|
+
} else {
|
|
9416
|
+
const videoModeQuery = this._videoMode ? `&videoMode=${this._videoMode}` : "";
|
|
9417
|
+
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync${videoModeQuery}`;
|
|
9418
|
+
if (this._params) {
|
|
9419
|
+
const params = JSON.stringify(this._params);
|
|
9420
|
+
const paramBlob = new Blob([params], { type: "application/json" });
|
|
9421
|
+
const formData = new FormData();
|
|
9422
|
+
const fileBlob = await new Response(this._uploadStream).blob();
|
|
9423
|
+
formData.append("params", paramBlob);
|
|
9424
|
+
formData.append("file", fileBlob);
|
|
9425
|
+
const headers = {
|
|
9426
|
+
...session.authenticationHeaders(),
|
|
9427
|
+
Accept: "application/jsonl"
|
|
9428
|
+
};
|
|
9429
|
+
response = await this._client.fetch(postUrl, {
|
|
9430
|
+
headers,
|
|
9431
|
+
method: "POST",
|
|
9432
|
+
body: formData,
|
|
9433
|
+
signal: this._controller.signal,
|
|
9434
|
+
// @ts-ignore
|
|
9435
|
+
duplex: "half",
|
|
9436
|
+
eyepop: { responseStreaming: true }
|
|
9437
|
+
});
|
|
9438
|
+
} else {
|
|
9439
|
+
const headers = {
|
|
9440
|
+
...session.authenticationHeaders(),
|
|
9441
|
+
Accept: "application/jsonl",
|
|
9442
|
+
"Content-Type": this._mimeType
|
|
9443
|
+
};
|
|
9444
|
+
if (this._size) {
|
|
9445
|
+
headers["Content-Length"] = `${this._size}`;
|
|
9457
9446
|
}
|
|
9447
|
+
response = await this._client.fetch(postUrl, {
|
|
9448
|
+
headers,
|
|
9449
|
+
method: "POST",
|
|
9450
|
+
body: this._uploadStream,
|
|
9451
|
+
signal: this._controller.signal,
|
|
9452
|
+
// @ts-ignore
|
|
9453
|
+
duplex: "half"
|
|
9454
|
+
});
|
|
9458
9455
|
}
|
|
9459
|
-
mid++;
|
|
9460
|
-
}
|
|
9461
|
-
return frag;
|
|
9462
|
-
}
|
|
9463
|
-
static unquoteCredential(v) {
|
|
9464
|
-
if (!v) {
|
|
9465
|
-
return "";
|
|
9466
9456
|
}
|
|
9467
|
-
return
|
|
9457
|
+
return response;
|
|
9468
9458
|
}
|
|
9469
9459
|
};
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
super(getSession, client, uuidv4().toString(), "liveIngress/whip", requestLogger);
|
|
9475
|
-
this._stream = stream;
|
|
9460
|
+
var LoadFromJob = class extends AbstractJob {
|
|
9461
|
+
constructor(location, params, getSession, client, requestLogger) {
|
|
9462
|
+
super(params, getSession, client, requestLogger);
|
|
9463
|
+
this._location = location;
|
|
9476
9464
|
}
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
const ingressUrl = this.gresUrl(session);
|
|
9480
|
-
const response = await this._client.fetch(ingressUrl, {
|
|
9481
|
-
headers: session.authenticationHeaders(),
|
|
9482
|
-
method: "GET"
|
|
9483
|
-
});
|
|
9484
|
-
if (response.status >= 300) {
|
|
9485
|
-
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9486
|
-
}
|
|
9487
|
-
return await this.onIceServers(response);
|
|
9465
|
+
get [Symbol.toStringTag]() {
|
|
9466
|
+
return "loadFromJob";
|
|
9488
9467
|
}
|
|
9489
|
-
async
|
|
9490
|
-
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
return Promise.reject("fetching stream failed");
|
|
9468
|
+
async startJob() {
|
|
9469
|
+
const session = await this._getSession();
|
|
9470
|
+
if (!session.baseUrl) {
|
|
9471
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9494
9472
|
}
|
|
9473
|
+
const body = {
|
|
9474
|
+
sourceType: "URL",
|
|
9475
|
+
url: this._location,
|
|
9476
|
+
params: this._params
|
|
9477
|
+
};
|
|
9478
|
+
const headers = {
|
|
9479
|
+
...session.authenticationHeaders(),
|
|
9480
|
+
Accept: "application/jsonl",
|
|
9481
|
+
"Content-Type": "application/json"
|
|
9482
|
+
};
|
|
9483
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9484
|
+
return await this._client.fetch(patchUrl, {
|
|
9485
|
+
headers,
|
|
9486
|
+
method: "PATCH",
|
|
9487
|
+
body: JSON.stringify(body),
|
|
9488
|
+
signal: this._controller.signal,
|
|
9489
|
+
// @ts-ignore
|
|
9490
|
+
eyepop: { responseStreaming: true }
|
|
9491
|
+
});
|
|
9495
9492
|
}
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
if (this._queuedCandidates.length !== 0) {
|
|
9502
|
-
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9503
|
-
this._queuedCandidates = [];
|
|
9504
|
-
}
|
|
9505
|
-
return this;
|
|
9493
|
+
};
|
|
9494
|
+
var LoadFromAssetUuidJob = class extends AbstractJob {
|
|
9495
|
+
constructor(assetUuid, params, getSession, client, requestLogger) {
|
|
9496
|
+
super(params, getSession, client, requestLogger);
|
|
9497
|
+
this._assetUuid = assetUuid;
|
|
9506
9498
|
}
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
throw new Error("onIceServers no stream");
|
|
9510
|
-
}
|
|
9511
|
-
const stream = this._stream;
|
|
9512
|
-
const pc = new RTCPeerConnection({
|
|
9513
|
-
iceServers: WebrtcBase.linkToIceServers(response.headers.get("Link"))
|
|
9514
|
-
});
|
|
9515
|
-
this._pc = pc;
|
|
9516
|
-
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9517
|
-
return new Promise(async (resolve, reject) => {
|
|
9518
|
-
pc.oniceconnectionstatechange = () => {
|
|
9519
|
-
switch (pc.iceConnectionState) {
|
|
9520
|
-
case "failed":
|
|
9521
|
-
case "disconnected":
|
|
9522
|
-
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9523
|
-
break;
|
|
9524
|
-
case "connected":
|
|
9525
|
-
resolve(this);
|
|
9526
|
-
break;
|
|
9527
|
-
}
|
|
9528
|
-
};
|
|
9529
|
-
stream.getTracks().forEach((track) => {
|
|
9530
|
-
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9531
|
-
pc.addTrack(track, stream);
|
|
9532
|
-
});
|
|
9533
|
-
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9534
|
-
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9535
|
-
pc.addTrack(trackEvent.track, stream);
|
|
9536
|
-
});
|
|
9537
|
-
await this.onLocalOffer(await pc.createOffer());
|
|
9538
|
-
});
|
|
9499
|
+
get [Symbol.toStringTag]() {
|
|
9500
|
+
return "loadFromAssetUuidJob";
|
|
9539
9501
|
}
|
|
9540
|
-
async
|
|
9541
|
-
const
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
const tracks = stream.getTracks();
|
|
9545
|
-
tracks.forEach((track) => {
|
|
9546
|
-
track.stop();
|
|
9547
|
-
});
|
|
9502
|
+
async startJob() {
|
|
9503
|
+
const session = await this._getSession();
|
|
9504
|
+
if (!session.baseUrl) {
|
|
9505
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9548
9506
|
}
|
|
9549
|
-
|
|
9507
|
+
const body = {
|
|
9508
|
+
sourceType: "ASSET_UUID",
|
|
9509
|
+
assetUuid: this._assetUuid,
|
|
9510
|
+
params: this._params
|
|
9511
|
+
};
|
|
9512
|
+
const headers = {
|
|
9513
|
+
...session.authenticationHeaders(),
|
|
9514
|
+
Accept: "application/jsonl",
|
|
9515
|
+
"Content-Type": "application/json"
|
|
9516
|
+
};
|
|
9517
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9518
|
+
return await this._client.fetch(patchUrl, {
|
|
9519
|
+
headers,
|
|
9520
|
+
method: "PATCH",
|
|
9521
|
+
body: JSON.stringify(body),
|
|
9522
|
+
signal: this._controller.signal,
|
|
9523
|
+
// @ts-ignore
|
|
9524
|
+
eyepop: { responseStreaming: true }
|
|
9525
|
+
});
|
|
9550
9526
|
}
|
|
9551
9527
|
};
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
super(getSession, client, ingressId, "liveIngress/whep", requestLogger);
|
|
9557
|
-
this._stream = null;
|
|
9558
|
-
}
|
|
9559
|
-
async close() {
|
|
9560
|
-
const stream = this._stream;
|
|
9561
|
-
this._stream = null;
|
|
9562
|
-
if (stream) {
|
|
9563
|
-
const tracks = stream.getTracks();
|
|
9564
|
-
tracks.forEach((track) => {
|
|
9565
|
-
track.stop();
|
|
9566
|
-
});
|
|
9567
|
-
}
|
|
9568
|
-
return super.close();
|
|
9528
|
+
var LoadLiveIngressJob = class extends AbstractJob {
|
|
9529
|
+
constructor(ingressId, params, getSession, client, requestLogger) {
|
|
9530
|
+
super(params, getSession, client, requestLogger);
|
|
9531
|
+
this._ingressId = ingressId;
|
|
9569
9532
|
}
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
return Promise.resolve(this._stream);
|
|
9573
|
-
} else {
|
|
9574
|
-
return Promise.reject("fetching stream failed");
|
|
9575
|
-
}
|
|
9533
|
+
get [Symbol.toStringTag]() {
|
|
9534
|
+
return "loadLiveIngressJob";
|
|
9576
9535
|
}
|
|
9577
|
-
async
|
|
9536
|
+
async startJob() {
|
|
9578
9537
|
const session = await this._getSession();
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
headers: session.authenticationHeaders(),
|
|
9582
|
-
method: "GET"
|
|
9583
|
-
});
|
|
9584
|
-
if (response.status >= 300) {
|
|
9585
|
-
return Promise.reject(`unknown status code for GET '${egressUrl}': ${response.status} (${response.statusText})`);
|
|
9538
|
+
if (!session.baseUrl) {
|
|
9539
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9586
9540
|
}
|
|
9587
|
-
|
|
9541
|
+
const body = {
|
|
9542
|
+
sourceType: "LIVE_INGRESS",
|
|
9543
|
+
liveIngressId: this._ingressId,
|
|
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=preempt&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
|
+
});
|
|
9588
9560
|
}
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
9594
|
-
if (this._queuedCandidates.length !== 0) {
|
|
9595
|
-
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9596
|
-
this._queuedCandidates = [];
|
|
9597
|
-
}
|
|
9598
|
-
return this;
|
|
9561
|
+
};
|
|
9562
|
+
var LoadMediaStreamJob = class extends AbstractJob {
|
|
9563
|
+
constructor(mediaStream, params, getSession, client, requestLogger) {
|
|
9564
|
+
super(params, getSession, client, requestLogger);
|
|
9565
|
+
this._mediaStream = mediaStream;
|
|
9599
9566
|
}
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9567
|
+
get [Symbol.toStringTag]() {
|
|
9568
|
+
return "loadLiveIngressJob";
|
|
9569
|
+
}
|
|
9570
|
+
async startJob() {
|
|
9571
|
+
const session = await this._getSession();
|
|
9572
|
+
if (!session.baseUrl) {
|
|
9573
|
+
return Promise.reject("session.baseUrl must not ne null");
|
|
9603
9574
|
}
|
|
9604
|
-
const
|
|
9605
|
-
|
|
9575
|
+
const whip = new WebrtcWhip(
|
|
9576
|
+
this._mediaStream,
|
|
9577
|
+
async () => {
|
|
9578
|
+
return session;
|
|
9579
|
+
},
|
|
9580
|
+
this._client,
|
|
9581
|
+
true,
|
|
9582
|
+
this._requestLogger
|
|
9583
|
+
);
|
|
9584
|
+
whip.start().then((value) => {
|
|
9585
|
+
this._requestLogger.debug("direct whip for ingressId=%s successful", whip.ingressId());
|
|
9586
|
+
}).catch((reason) => {
|
|
9587
|
+
this._controller.abort(reason);
|
|
9606
9588
|
});
|
|
9607
|
-
const
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
case "connected":
|
|
9626
|
-
this._requestLogger.debug("oniceconnectionstatechange connected");
|
|
9627
|
-
break;
|
|
9628
|
-
}
|
|
9629
|
-
};
|
|
9630
|
-
await this.onLocalOffer(await pc.createOffer());
|
|
9589
|
+
const body = {
|
|
9590
|
+
sourceType: "WHIP",
|
|
9591
|
+
whipIngressId: whip.ingressId(),
|
|
9592
|
+
params: this._params
|
|
9593
|
+
};
|
|
9594
|
+
const headers = {
|
|
9595
|
+
...session.authenticationHeaders(),
|
|
9596
|
+
Accept: "application/jsonl",
|
|
9597
|
+
"Content-Type": "application/json"
|
|
9598
|
+
};
|
|
9599
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=preempt&processing=sync`;
|
|
9600
|
+
return await this._client.fetch(patchUrl, {
|
|
9601
|
+
headers,
|
|
9602
|
+
method: "PATCH",
|
|
9603
|
+
body: JSON.stringify(body),
|
|
9604
|
+
signal: this._controller.signal,
|
|
9605
|
+
// @ts-ignore
|
|
9606
|
+
eyepop: { responseStreaming: true }
|
|
9631
9607
|
});
|
|
9632
9608
|
}
|
|
9633
9609
|
};
|
|
@@ -10141,8 +10117,6 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10141
10117
|
this._pipelineId = null;
|
|
10142
10118
|
this._popName = null;
|
|
10143
10119
|
this._pipeline = null;
|
|
10144
|
-
this._ingressEventHandler = null;
|
|
10145
|
-
this._ingressEventWs = null;
|
|
10146
10120
|
this._sandboxId = null;
|
|
10147
10121
|
const sessionAuth = options.auth;
|
|
10148
10122
|
if (sessionAuth !== void 0 && sessionAuth.session !== void 0) {
|
|
@@ -10168,7 +10142,7 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10168
10142
|
});
|
|
10169
10143
|
if (response?.status != 204) {
|
|
10170
10144
|
const message = await response?.text();
|
|
10171
|
-
this._logger.info(`
|
|
10145
|
+
this._logger.info(`stopping pipeline failed, status ${response?.status}: ${message}`);
|
|
10172
10146
|
}
|
|
10173
10147
|
}
|
|
10174
10148
|
if (this._sandboxId && this._baseUrl) {
|
|
@@ -10342,42 +10316,6 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10342
10316
|
popId() {
|
|
10343
10317
|
return this.options().popId || null;
|
|
10344
10318
|
}
|
|
10345
|
-
onIngressEvent(handler) {
|
|
10346
|
-
this._ingressEventHandler = handler;
|
|
10347
|
-
this.startIngressWs().then(() => {
|
|
10348
|
-
}).catch((reason) => {
|
|
10349
|
-
this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
|
|
10350
|
-
});
|
|
10351
|
-
return this;
|
|
10352
|
-
}
|
|
10353
|
-
async liveIngress(stream) {
|
|
10354
|
-
if (!this._baseUrl || !this._client) {
|
|
10355
|
-
return Promise.reject("endpoint not connected, use connect()");
|
|
10356
|
-
}
|
|
10357
|
-
const whip = new WebrtcWhip(
|
|
10358
|
-
stream,
|
|
10359
|
-
async () => {
|
|
10360
|
-
return this.session();
|
|
10361
|
-
},
|
|
10362
|
-
this._client,
|
|
10363
|
-
this._requestLogger
|
|
10364
|
-
);
|
|
10365
|
-
return whip.start();
|
|
10366
|
-
}
|
|
10367
|
-
async liveEgress(ingressId) {
|
|
10368
|
-
if (!this._baseUrl || !this._client) {
|
|
10369
|
-
return Promise.reject("endpoint not connected, use connect()");
|
|
10370
|
-
}
|
|
10371
|
-
const whep = new WebrtcWhep(
|
|
10372
|
-
ingressId,
|
|
10373
|
-
async () => {
|
|
10374
|
-
return this.session();
|
|
10375
|
-
},
|
|
10376
|
-
this._client,
|
|
10377
|
-
this._requestLogger
|
|
10378
|
-
);
|
|
10379
|
-
return whep.start();
|
|
10380
|
-
}
|
|
10381
10319
|
async process(source, params) {
|
|
10382
10320
|
if (source.file !== void 0) {
|
|
10383
10321
|
return this.uploadFile(source, params);
|
|
@@ -10387,45 +10325,14 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10387
10325
|
return this.uploadPath(source, params);
|
|
10388
10326
|
} else if (source.url !== void 0) {
|
|
10389
10327
|
return this.loadFrom(source, params);
|
|
10390
|
-
} else if (source.ingressId !== void 0) {
|
|
10391
|
-
return this.loadLiveIngress(source, params);
|
|
10392
10328
|
} else if (source.assetUuid !== void 0) {
|
|
10393
10329
|
return this.loadFromAssetUuid(source, params);
|
|
10330
|
+
} else if (source.mediaStream !== void 0) {
|
|
10331
|
+
return this.loadMediaStream(source, params);
|
|
10394
10332
|
} else {
|
|
10395
10333
|
return Promise.reject("unknown source type");
|
|
10396
10334
|
}
|
|
10397
10335
|
}
|
|
10398
|
-
async startIngressWs() {
|
|
10399
|
-
const client = this._client;
|
|
10400
|
-
if (this._ingressEventWs || !this._baseUrl || !client) {
|
|
10401
|
-
return;
|
|
10402
|
-
}
|
|
10403
|
-
try {
|
|
10404
|
-
const session = await this.session();
|
|
10405
|
-
let response = await this.fetchWithRetry(async () => {
|
|
10406
|
-
const headers = {
|
|
10407
|
-
...this._authenticationHeaders(session)
|
|
10408
|
-
};
|
|
10409
|
-
const getTokenUrl = `${session.baseUrl}/liveIngress/events/token`;
|
|
10410
|
-
return client.fetch(getTokenUrl, { headers });
|
|
10411
|
-
});
|
|
10412
|
-
if (response.status != 200) {
|
|
10413
|
-
const message = await response.text();
|
|
10414
|
-
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
10415
|
-
}
|
|
10416
|
-
const wsAuthToken = await response.json();
|
|
10417
|
-
const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
|
|
10418
|
-
this._ingressEventWs = new WebSocket(wsUrl);
|
|
10419
|
-
this._ingressEventWs.addEventListener("message", (event) => {
|
|
10420
|
-
const ingressEvent = JSON.parse(event.data);
|
|
10421
|
-
if (this._ingressEventHandler) {
|
|
10422
|
-
this._ingressEventHandler(ingressEvent);
|
|
10423
|
-
}
|
|
10424
|
-
});
|
|
10425
|
-
} finally {
|
|
10426
|
-
this.updateState();
|
|
10427
|
-
}
|
|
10428
|
-
}
|
|
10429
10336
|
async uploadFile(source, params) {
|
|
10430
10337
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10431
10338
|
return Promise.reject("endpoint not connected, use connect()");
|
|
@@ -10591,15 +10498,15 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10591
10498
|
throw e;
|
|
10592
10499
|
}
|
|
10593
10500
|
}
|
|
10594
|
-
async
|
|
10501
|
+
async loadMediaStream(source, params) {
|
|
10595
10502
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10596
10503
|
throw new Error("endpoint not connected, use connect()");
|
|
10597
10504
|
}
|
|
10598
10505
|
await this._limit.acquire();
|
|
10599
10506
|
try {
|
|
10600
10507
|
this.updateState();
|
|
10601
|
-
const job = new
|
|
10602
|
-
source.
|
|
10508
|
+
const job = new LoadMediaStreamJob(
|
|
10509
|
+
source.mediaStream,
|
|
10603
10510
|
params,
|
|
10604
10511
|
async () => {
|
|
10605
10512
|
return this.session();
|
|
@@ -10747,9 +10654,6 @@ var WorkerEndpoint = class extends Endpoint {
|
|
|
10747
10654
|
}
|
|
10748
10655
|
}
|
|
10749
10656
|
}
|
|
10750
|
-
if (!this._ingressEventWs && this._ingressEventHandler) {
|
|
10751
|
-
await this.startIngressWs();
|
|
10752
|
-
}
|
|
10753
10657
|
this.updateState();
|
|
10754
10658
|
return Promise.resolve(this);
|
|
10755
10659
|
}
|
|
@@ -11658,6 +11562,88 @@ var DataEndpoint = class extends Endpoint {
|
|
|
11658
11562
|
}
|
|
11659
11563
|
};
|
|
11660
11564
|
|
|
11565
|
+
// worker/webrtc_whep.ts
|
|
11566
|
+
var WebrtcWhep = class extends WebrtcBase {
|
|
11567
|
+
constructor(ingressId, getSession, client, requestLogger) {
|
|
11568
|
+
super(getSession, client, ingressId, "liveIngress/whep", false, requestLogger);
|
|
11569
|
+
this._stream = null;
|
|
11570
|
+
}
|
|
11571
|
+
async close() {
|
|
11572
|
+
const stream = this._stream;
|
|
11573
|
+
this._stream = null;
|
|
11574
|
+
if (stream) {
|
|
11575
|
+
const tracks = stream.getTracks();
|
|
11576
|
+
tracks.forEach((track) => {
|
|
11577
|
+
track.stop();
|
|
11578
|
+
});
|
|
11579
|
+
}
|
|
11580
|
+
return super.close();
|
|
11581
|
+
}
|
|
11582
|
+
async stream() {
|
|
11583
|
+
if (this._stream) {
|
|
11584
|
+
return Promise.resolve(this._stream);
|
|
11585
|
+
} else {
|
|
11586
|
+
return Promise.reject("fetching stream failed");
|
|
11587
|
+
}
|
|
11588
|
+
}
|
|
11589
|
+
async start() {
|
|
11590
|
+
const session = await this._getSession();
|
|
11591
|
+
const egressUrl = this.gresUrl(session);
|
|
11592
|
+
const response = await this._client.fetch(egressUrl, {
|
|
11593
|
+
headers: session.authenticationHeaders(),
|
|
11594
|
+
method: "GET"
|
|
11595
|
+
});
|
|
11596
|
+
if (response.status >= 300) {
|
|
11597
|
+
return Promise.reject(`unknown status code for GET '${egressUrl}': ${response.status} (${response.statusText})`);
|
|
11598
|
+
}
|
|
11599
|
+
return this.onIceServers(response);
|
|
11600
|
+
}
|
|
11601
|
+
async onRemoteAnswer(answer) {
|
|
11602
|
+
if (!this._pc) {
|
|
11603
|
+
throw new Error("onLocalOffer no peer connection");
|
|
11604
|
+
}
|
|
11605
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
11606
|
+
if (this._queuedCandidates.length !== 0) {
|
|
11607
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
11608
|
+
this._queuedCandidates = [];
|
|
11609
|
+
}
|
|
11610
|
+
return this;
|
|
11611
|
+
}
|
|
11612
|
+
async onIceServers(response) {
|
|
11613
|
+
if (this._stream) {
|
|
11614
|
+
throw new Error("onIceServers has stream");
|
|
11615
|
+
}
|
|
11616
|
+
const pc = new RTCPeerConnection({
|
|
11617
|
+
iceServers: WebrtcBase.linkToIceServers(response.headers.get("Link"))
|
|
11618
|
+
});
|
|
11619
|
+
const direction = "sendrecv";
|
|
11620
|
+
pc.addTransceiver("video", { direction });
|
|
11621
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
11622
|
+
this._pc = pc;
|
|
11623
|
+
this._requestLogger.info(`onIceServers ${pc.iceConnectionState}`);
|
|
11624
|
+
return new Promise(async (resolve, reject) => {
|
|
11625
|
+
pc.ontrack = (evt) => {
|
|
11626
|
+
this._requestLogger.debug(`new track: ${evt.track.kind}`);
|
|
11627
|
+
this._stream = evt.streams[0];
|
|
11628
|
+
resolve(this);
|
|
11629
|
+
};
|
|
11630
|
+
pc.oniceconnectionstatechange = () => {
|
|
11631
|
+
switch (pc.iceConnectionState) {
|
|
11632
|
+
case "failed":
|
|
11633
|
+
case "disconnected":
|
|
11634
|
+
this._requestLogger.debug("oniceconnectionstatechange disconnected");
|
|
11635
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
11636
|
+
break;
|
|
11637
|
+
case "connected":
|
|
11638
|
+
this._requestLogger.debug("oniceconnectionstatechange connected");
|
|
11639
|
+
break;
|
|
11640
|
+
}
|
|
11641
|
+
};
|
|
11642
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
11643
|
+
});
|
|
11644
|
+
}
|
|
11645
|
+
};
|
|
11646
|
+
|
|
11661
11647
|
// index.ts
|
|
11662
11648
|
var readEnv = (env) => {
|
|
11663
11649
|
if (typeof process !== "undefined") {
|
|
@@ -11792,6 +11778,7 @@ export {
|
|
|
11792
11778
|
LoadFromAssetUuidJob,
|
|
11793
11779
|
LoadFromJob,
|
|
11794
11780
|
LoadLiveIngressJob,
|
|
11781
|
+
LoadMediaStreamJob,
|
|
11795
11782
|
ModelExportStatus,
|
|
11796
11783
|
ModelFormat,
|
|
11797
11784
|
ModelPrecisionType,
|