@roboflow/inference-sdk 0.1.10 → 0.1.12
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/index.es.js +171 -159
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/inference-api.d.ts +4 -1
- package/dist/inference-api.d.ts.map +1 -1
- package/dist/webrtc.d.ts +8 -0
- package/dist/webrtc.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
var q = Object.defineProperty;
|
|
2
2
|
var K = (r, e, t) => e in r ? q(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
|
|
3
3
|
var l = (r, e, t) => K(r, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
-
var
|
|
5
|
-
const
|
|
4
|
+
var I;
|
|
5
|
+
const j = typeof process < "u" && ((I = process.env) != null && I.RF_API_BASE_URL) ? process.env.RF_API_BASE_URL : "https://api.roboflow.com", V = [
|
|
6
6
|
"https://serverless.roboflow.com"
|
|
7
7
|
];
|
|
8
|
-
class
|
|
8
|
+
class b {
|
|
9
9
|
/**
|
|
10
10
|
* @private
|
|
11
11
|
* Use InferenceHTTPClient.init() instead
|
|
12
12
|
*/
|
|
13
|
-
constructor(e, t = "https://serverless.roboflow.com") {
|
|
13
|
+
constructor(e, t = "https://serverless.roboflow.com", n = j) {
|
|
14
14
|
l(this, "apiKey");
|
|
15
15
|
l(this, "serverUrl");
|
|
16
|
-
this
|
|
16
|
+
l(this, "apiBaseUrl");
|
|
17
|
+
this.apiKey = e, this.serverUrl = t, this.apiBaseUrl = n;
|
|
17
18
|
}
|
|
18
|
-
static init({ apiKey: e, serverUrl: t }) {
|
|
19
|
+
static init({ apiKey: e, serverUrl: t, apiBaseUrl: n }) {
|
|
19
20
|
if (!e)
|
|
20
21
|
throw new Error("apiKey is required");
|
|
21
|
-
return new
|
|
22
|
+
return new b(e, t, n);
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* Initialize a WebRTC worker pipeline
|
|
@@ -49,15 +50,15 @@ class T {
|
|
|
49
50
|
offer: e,
|
|
50
51
|
workflowSpec: t,
|
|
51
52
|
workspaceName: n,
|
|
52
|
-
workflowId:
|
|
53
|
-
config:
|
|
53
|
+
workflowId: a,
|
|
54
|
+
config: o = {}
|
|
54
55
|
}) {
|
|
55
56
|
if (!e || !e.sdp || !e.type)
|
|
56
57
|
throw new Error("offer with sdp and type is required");
|
|
57
|
-
const i = !!t,
|
|
58
|
-
if (!i && !
|
|
58
|
+
const i = !!t, f = !!(n && a);
|
|
59
|
+
if (!i && !f)
|
|
59
60
|
throw new Error("Either workflowSpec OR (workspaceName + workflowId) is required");
|
|
60
|
-
if (i &&
|
|
61
|
+
if (i && f)
|
|
61
62
|
throw new Error("Provide either workflowSpec OR (workspaceName + workflowId), not both");
|
|
62
63
|
const {
|
|
63
64
|
imageInputName: d = "image",
|
|
@@ -65,13 +66,13 @@ class T {
|
|
|
65
66
|
dataOutputNames: s = [],
|
|
66
67
|
threadPoolWorkers: y = 4,
|
|
67
68
|
workflowsParameters: S = {},
|
|
68
|
-
iceServers:
|
|
69
|
+
iceServers: p,
|
|
69
70
|
processingTimeout: u,
|
|
70
|
-
requestedPlan:
|
|
71
|
+
requestedPlan: h,
|
|
71
72
|
requestedRegion: C,
|
|
72
|
-
realtimeProcessing:
|
|
73
|
+
realtimeProcessing: E = !0,
|
|
73
74
|
rtspUrl: R
|
|
74
|
-
} =
|
|
75
|
+
} = o, v = {
|
|
75
76
|
type: "WorkflowConfiguration",
|
|
76
77
|
image_input_name: d,
|
|
77
78
|
workflows_parameters: S,
|
|
@@ -79,28 +80,28 @@ class T {
|
|
|
79
80
|
cancel_thread_pool_tasks_on_exit: !0,
|
|
80
81
|
video_metadata_input_name: "video_metadata"
|
|
81
82
|
};
|
|
82
|
-
i ? v.workflow_specification = t : (v.workspace_name = n, v.workflow_id =
|
|
83
|
+
i ? v.workflow_specification = t : (v.workspace_name = n, v.workflow_id = a);
|
|
83
84
|
const m = {
|
|
84
85
|
workflow_configuration: v,
|
|
85
86
|
api_key: this.apiKey,
|
|
86
|
-
webrtc_realtime_processing:
|
|
87
|
+
webrtc_realtime_processing: E,
|
|
87
88
|
webrtc_offer: {
|
|
88
89
|
sdp: e.sdp,
|
|
89
90
|
type: e.type
|
|
90
91
|
},
|
|
91
|
-
webrtc_config:
|
|
92
|
+
webrtc_config: p ? { iceServers: p } : null,
|
|
92
93
|
stream_output: c,
|
|
93
94
|
data_output: s
|
|
94
95
|
};
|
|
95
|
-
u !== void 0 && (m.processing_timeout = u),
|
|
96
|
+
u !== void 0 && (m.processing_timeout = u), h !== void 0 && (m.requested_plan = h), C !== void 0 && (m.requested_region = C), R && (m.rtsp_url = R);
|
|
96
97
|
const w = await fetch(`${this.serverUrl}/initialise_webrtc_worker`, {
|
|
97
98
|
method: "POST",
|
|
98
99
|
headers: { "Content-Type": "application/json" },
|
|
99
100
|
body: JSON.stringify(m)
|
|
100
101
|
});
|
|
101
102
|
if (!w.ok) {
|
|
102
|
-
const
|
|
103
|
-
throw new Error(`initialise_webrtc_worker failed (${w.status}): ${
|
|
103
|
+
const T = await w.text().catch(() => "");
|
|
104
|
+
throw new Error(`initialise_webrtc_worker failed (${w.status}): ${T}`);
|
|
104
105
|
}
|
|
105
106
|
return await w.json();
|
|
106
107
|
}
|
|
@@ -132,11 +133,11 @@ class T {
|
|
|
132
133
|
* ```
|
|
133
134
|
*/
|
|
134
135
|
async fetchTurnConfig() {
|
|
135
|
-
if (!
|
|
136
|
+
if (!V.includes(this.serverUrl))
|
|
136
137
|
return null;
|
|
137
138
|
try {
|
|
138
139
|
const e = await fetch(
|
|
139
|
-
`${
|
|
140
|
+
`${this.apiBaseUrl}/webrtc_turn_config?api_key=${this.apiKey}`,
|
|
140
141
|
{
|
|
141
142
|
method: "GET",
|
|
142
143
|
headers: { "Content-Type": "application/json" }
|
|
@@ -154,17 +155,17 @@ class T {
|
|
|
154
155
|
n = [t];
|
|
155
156
|
else
|
|
156
157
|
return console.warn("[RFWebRTC] Invalid TURN config format, using defaults"), null;
|
|
157
|
-
return n.map((
|
|
158
|
-
urls: Array.isArray(
|
|
159
|
-
username:
|
|
160
|
-
credential:
|
|
158
|
+
return n.map((o) => ({
|
|
159
|
+
urls: Array.isArray(o.urls) ? o.urls : [o.urls],
|
|
160
|
+
username: o.username,
|
|
161
|
+
credential: o.credential
|
|
161
162
|
}));
|
|
162
163
|
} catch (e) {
|
|
163
164
|
return console.warn("[RFWebRTC] Error fetching TURN config:", e), null;
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
|
-
const
|
|
168
|
+
const ie = {
|
|
168
169
|
/**
|
|
169
170
|
* Create a connector that uses API key directly
|
|
170
171
|
*
|
|
@@ -184,35 +185,35 @@ const ae = {
|
|
|
184
185
|
* ```
|
|
185
186
|
*/
|
|
186
187
|
withApiKey(r, e = {}) {
|
|
187
|
-
const { serverUrl: t } = e;
|
|
188
|
+
const { serverUrl: t, apiBaseUrl: n } = e;
|
|
188
189
|
typeof window < "u" && console.warn(
|
|
189
190
|
"[Security Warning] Using API key directly in browser will expose it. Use connectors.withProxyUrl() for production. See: https://docs.roboflow.com/api-reference/authentication#securing-your-api-key"
|
|
190
191
|
);
|
|
191
|
-
const
|
|
192
|
+
const a = b.init({ apiKey: r, serverUrl: t, apiBaseUrl: n });
|
|
192
193
|
return {
|
|
193
|
-
connectWrtc: async (o,
|
|
194
|
+
connectWrtc: async (o, i) => (console.debug("wrtcParams", i), await a.initializeWebrtcWorker({
|
|
194
195
|
offer: o,
|
|
195
|
-
workflowSpec:
|
|
196
|
-
workspaceName:
|
|
197
|
-
workflowId:
|
|
196
|
+
workflowSpec: i.workflowSpec,
|
|
197
|
+
workspaceName: i.workspaceName,
|
|
198
|
+
workflowId: i.workflowId,
|
|
198
199
|
config: {
|
|
199
|
-
imageInputName:
|
|
200
|
-
streamOutputNames:
|
|
201
|
-
dataOutputNames:
|
|
202
|
-
threadPoolWorkers:
|
|
203
|
-
workflowsParameters:
|
|
204
|
-
iceServers:
|
|
205
|
-
processingTimeout:
|
|
206
|
-
requestedPlan:
|
|
207
|
-
requestedRegion:
|
|
208
|
-
realtimeProcessing:
|
|
209
|
-
rtspUrl:
|
|
200
|
+
imageInputName: i.imageInputName,
|
|
201
|
+
streamOutputNames: i.streamOutputNames,
|
|
202
|
+
dataOutputNames: i.dataOutputNames,
|
|
203
|
+
threadPoolWorkers: i.threadPoolWorkers,
|
|
204
|
+
workflowsParameters: i.workflowsParameters,
|
|
205
|
+
iceServers: i.iceServers,
|
|
206
|
+
processingTimeout: i.processingTimeout,
|
|
207
|
+
requestedPlan: i.requestedPlan,
|
|
208
|
+
requestedRegion: i.requestedRegion,
|
|
209
|
+
realtimeProcessing: i.realtimeProcessing,
|
|
210
|
+
rtspUrl: i.rtspUrl
|
|
210
211
|
}
|
|
211
212
|
})),
|
|
212
213
|
/**
|
|
213
214
|
* Fetch TURN server configuration for improved WebRTC connectivity
|
|
214
215
|
*/
|
|
215
|
-
getIceServers: async () => await
|
|
216
|
+
getIceServers: async () => await a.fetchTurnConfig(),
|
|
216
217
|
// Store apiKey for cleanup
|
|
217
218
|
_apiKey: r,
|
|
218
219
|
_serverUrl: t
|
|
@@ -284,20 +285,20 @@ const ae = {
|
|
|
284
285
|
withProxyUrl(r, e = {}) {
|
|
285
286
|
const { turnConfigUrl: t } = e;
|
|
286
287
|
return {
|
|
287
|
-
connectWrtc: async (n,
|
|
288
|
-
const
|
|
288
|
+
connectWrtc: async (n, a) => {
|
|
289
|
+
const o = await fetch(r, {
|
|
289
290
|
method: "POST",
|
|
290
291
|
headers: { "Content-Type": "application/json" },
|
|
291
292
|
body: JSON.stringify({
|
|
292
293
|
offer: n,
|
|
293
|
-
wrtcParams:
|
|
294
|
+
wrtcParams: a
|
|
294
295
|
})
|
|
295
296
|
});
|
|
296
|
-
if (!
|
|
297
|
-
const i = await
|
|
298
|
-
throw new Error(`Proxy request failed (${
|
|
297
|
+
if (!o.ok) {
|
|
298
|
+
const i = await o.text().catch(() => "");
|
|
299
|
+
throw new Error(`Proxy request failed (${o.status}): ${i}`);
|
|
299
300
|
}
|
|
300
|
-
return await
|
|
301
|
+
return await o.json();
|
|
301
302
|
},
|
|
302
303
|
/**
|
|
303
304
|
* Fetch TURN server configuration from the proxy backend
|
|
@@ -317,7 +318,7 @@ const ae = {
|
|
|
317
318
|
};
|
|
318
319
|
}
|
|
319
320
|
};
|
|
320
|
-
async function
|
|
321
|
+
async function $(r = { video: !0 }) {
|
|
321
322
|
try {
|
|
322
323
|
console.log("[RFStreams] requesting with", r);
|
|
323
324
|
const e = await navigator.mediaDevices.getUserMedia(r);
|
|
@@ -334,9 +335,9 @@ function O(r) {
|
|
|
334
335
|
const oe = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
335
336
|
__proto__: null,
|
|
336
337
|
stopStream: O,
|
|
337
|
-
useCamera:
|
|
338
|
-
}, Symbol.toStringTag, { value: "Module" })), k = 49152,
|
|
339
|
-
function
|
|
338
|
+
useCamera: $
|
|
339
|
+
}, Symbol.toStringTag, { value: "Module" })), k = 49152, M = 262144, z = 10;
|
|
340
|
+
function H(r) {
|
|
340
341
|
return new Promise((e) => setTimeout(e, r));
|
|
341
342
|
}
|
|
342
343
|
class D {
|
|
@@ -365,17 +366,17 @@ class D {
|
|
|
365
366
|
throw new Error("Upload cancelled");
|
|
366
367
|
if (this.channel.readyState !== "open")
|
|
367
368
|
throw new Error("Video upload interrupted");
|
|
368
|
-
const
|
|
369
|
-
for (c.setUint32(0, n, !0), c.setUint32(4, this.totalChunks, !0), new Uint8Array(d, 8).set(
|
|
369
|
+
const a = n * k, o = Math.min(a + k, t), i = this.file.slice(a, o), f = new Uint8Array(await i.arrayBuffer()), d = new ArrayBuffer(8 + f.length), c = new DataView(d);
|
|
370
|
+
for (c.setUint32(0, n, !0), c.setUint32(4, this.totalChunks, !0), new Uint8Array(d, 8).set(f); this.channel.bufferedAmount > M; ) {
|
|
370
371
|
if (this.channel.readyState !== "open")
|
|
371
372
|
throw new Error("Video upload interrupted");
|
|
372
|
-
await z
|
|
373
|
+
await H(z);
|
|
373
374
|
}
|
|
374
|
-
this.channel.send(d), e && e(
|
|
375
|
+
this.channel.send(d), e && e(o, t);
|
|
375
376
|
}
|
|
376
377
|
}
|
|
377
378
|
}
|
|
378
|
-
const
|
|
379
|
+
const J = 12;
|
|
379
380
|
class N {
|
|
380
381
|
constructor() {
|
|
381
382
|
l(this, "pendingFrames", /* @__PURE__ */ new Map());
|
|
@@ -383,22 +384,22 @@ class N {
|
|
|
383
384
|
/**
|
|
384
385
|
* Process an incoming chunk and return the complete message if all chunks received
|
|
385
386
|
*/
|
|
386
|
-
processChunk(e, t, n,
|
|
387
|
+
processChunk(e, t, n, a) {
|
|
387
388
|
if (n === 1)
|
|
388
|
-
return
|
|
389
|
+
return a;
|
|
389
390
|
this.pendingFrames.has(e) || this.pendingFrames.set(e, {
|
|
390
391
|
chunks: /* @__PURE__ */ new Map(),
|
|
391
392
|
totalChunks: n
|
|
392
393
|
});
|
|
393
|
-
const
|
|
394
|
-
if (
|
|
395
|
-
const i = Array.from(
|
|
394
|
+
const o = this.pendingFrames.get(e);
|
|
395
|
+
if (o.chunks.set(t, a), o.chunks.size === n) {
|
|
396
|
+
const i = Array.from(o.chunks.values()).reduce((c, s) => c + s.length, 0), f = new Uint8Array(i);
|
|
396
397
|
let d = 0;
|
|
397
398
|
for (let c = 0; c < n; c++) {
|
|
398
|
-
const s =
|
|
399
|
-
|
|
399
|
+
const s = o.chunks.get(c);
|
|
400
|
+
f.set(s, d), d += s.length;
|
|
400
401
|
}
|
|
401
|
-
return this.pendingFrames.delete(e),
|
|
402
|
+
return this.pendingFrames.delete(e), f;
|
|
402
403
|
}
|
|
403
404
|
return null;
|
|
404
405
|
}
|
|
@@ -410,27 +411,27 @@ class N {
|
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
413
|
function A(r) {
|
|
413
|
-
const e = new DataView(r), t = e.getUint32(0, !0), n = e.getUint32(4, !0),
|
|
414
|
-
return { frameId: t, chunkIndex: n, totalChunks:
|
|
414
|
+
const e = new DataView(r), t = e.getUint32(0, !0), n = e.getUint32(4, !0), a = e.getUint32(8, !0), o = new Uint8Array(r, J);
|
|
415
|
+
return { frameId: t, chunkIndex: n, totalChunks: a, payload: o };
|
|
415
416
|
}
|
|
416
417
|
async function G(r, e = 6e3) {
|
|
417
418
|
if (r.iceGatheringState === "complete") return;
|
|
418
419
|
let t = !1;
|
|
419
|
-
const n = (
|
|
420
|
-
|
|
420
|
+
const n = (a) => {
|
|
421
|
+
a.candidate && a.candidate.type === "srflx" && (t = !0);
|
|
421
422
|
};
|
|
422
423
|
r.addEventListener("icecandidate", n);
|
|
423
424
|
try {
|
|
424
425
|
await Promise.race([
|
|
425
|
-
new Promise((
|
|
426
|
-
const
|
|
427
|
-
r.iceGatheringState === "complete" && (r.removeEventListener("icegatheringstatechange",
|
|
426
|
+
new Promise((a) => {
|
|
427
|
+
const o = () => {
|
|
428
|
+
r.iceGatheringState === "complete" && (r.removeEventListener("icegatheringstatechange", o), a());
|
|
428
429
|
};
|
|
429
|
-
r.addEventListener("icegatheringstatechange",
|
|
430
|
+
r.addEventListener("icegatheringstatechange", o);
|
|
430
431
|
}),
|
|
431
|
-
new Promise((
|
|
432
|
+
new Promise((a, o) => {
|
|
432
433
|
setTimeout(() => {
|
|
433
|
-
t ?
|
|
434
|
+
t ? a() : (console.error("[ICE] timeout with NO srflx candidate! Connection may fail."), o(new Error("ICE gathering timeout without srflx candidate")));
|
|
434
435
|
}, e);
|
|
435
436
|
})
|
|
436
437
|
]);
|
|
@@ -438,52 +439,52 @@ async function G(r, e = 6e3) {
|
|
|
438
439
|
r.removeEventListener("icecandidate", n);
|
|
439
440
|
}
|
|
440
441
|
}
|
|
441
|
-
function
|
|
442
|
+
function Z(r) {
|
|
442
443
|
return new Promise((e) => {
|
|
443
444
|
r.addEventListener("track", (t) => {
|
|
444
445
|
t.streams && t.streams[0] && e(t.streams[0]);
|
|
445
446
|
});
|
|
446
447
|
});
|
|
447
448
|
}
|
|
448
|
-
const
|
|
449
|
+
const Q = [
|
|
449
450
|
{ urls: ["stun:stun.l.google.com:19302"] }
|
|
450
451
|
];
|
|
451
|
-
async function
|
|
452
|
+
async function X(r, e, t, n, a) {
|
|
452
453
|
if ([!!r, !!e, !!n].filter(Boolean).length !== 1)
|
|
453
454
|
throw new Error("Exactly one of localStream, file, or rtspUrl must be provided");
|
|
454
|
-
const c = t ??
|
|
455
|
+
const c = t ?? Q, s = new RTCPeerConnection({
|
|
455
456
|
iceServers: c
|
|
456
457
|
});
|
|
457
|
-
|
|
458
|
+
a != null && a.onPeerConnectionCreated && await a.onPeerConnectionCreated(s);
|
|
458
459
|
try {
|
|
459
460
|
s.addTransceiver("video", { direction: "recvonly" });
|
|
460
|
-
} catch (
|
|
461
|
-
console.warn("[RFWebRTC] Could not add transceiver:",
|
|
461
|
+
} catch (h) {
|
|
462
|
+
console.warn("[RFWebRTC] Could not add transceiver:", h);
|
|
462
463
|
}
|
|
463
464
|
if (r)
|
|
464
|
-
for (const
|
|
465
|
-
const C = s.addTrack(
|
|
466
|
-
|
|
465
|
+
for (const h of r.getVideoTracks()) {
|
|
466
|
+
const C = s.addTrack(h, r);
|
|
467
|
+
a != null && a.onTrackAdded && await a.onTrackAdded(h, C, s);
|
|
467
468
|
}
|
|
468
|
-
const y =
|
|
469
|
+
const y = Z(s), S = s.createDataChannel("inference", {
|
|
469
470
|
ordered: !0
|
|
470
471
|
});
|
|
471
|
-
let
|
|
472
|
-
e && (
|
|
472
|
+
let p;
|
|
473
|
+
e && (p = s.createDataChannel("video_upload"));
|
|
473
474
|
let u = await s.createOffer();
|
|
474
|
-
if (
|
|
475
|
-
const
|
|
476
|
-
|
|
475
|
+
if (a != null && a.onOfferCreated) {
|
|
476
|
+
const h = await a.onOfferCreated(u);
|
|
477
|
+
h && (u = h);
|
|
477
478
|
}
|
|
478
479
|
return await s.setLocalDescription(u), await G(s), {
|
|
479
480
|
pc: s,
|
|
480
481
|
offer: s.localDescription,
|
|
481
482
|
remoteStreamPromise: y,
|
|
482
483
|
dataChannel: S,
|
|
483
|
-
uploadChannel:
|
|
484
|
+
uploadChannel: p
|
|
484
485
|
};
|
|
485
486
|
}
|
|
486
|
-
async function
|
|
487
|
+
async function Y(r) {
|
|
487
488
|
const e = r.getSenders().find((n) => n.track && n.track.kind === "video");
|
|
488
489
|
if (!e) return;
|
|
489
490
|
const t = e.getParameters();
|
|
@@ -494,25 +495,25 @@ async function X(r) {
|
|
|
494
495
|
console.warn("[RFWebRTC] Failed to set encoding parameters:", n);
|
|
495
496
|
}
|
|
496
497
|
}
|
|
497
|
-
function
|
|
498
|
+
function ee(r, e = 3e4) {
|
|
498
499
|
return new Promise((t, n) => {
|
|
499
500
|
if (r.readyState === "open") {
|
|
500
501
|
t();
|
|
501
502
|
return;
|
|
502
503
|
}
|
|
503
|
-
const
|
|
504
|
-
r.removeEventListener("open",
|
|
505
|
-
},
|
|
506
|
-
r.removeEventListener("open",
|
|
504
|
+
const a = () => {
|
|
505
|
+
r.removeEventListener("open", a), r.removeEventListener("error", o), clearTimeout(i), t();
|
|
506
|
+
}, o = () => {
|
|
507
|
+
r.removeEventListener("open", a), r.removeEventListener("error", o), clearTimeout(i), n(new Error("Datachannel error"));
|
|
507
508
|
}, i = setTimeout(() => {
|
|
508
|
-
r.removeEventListener("open",
|
|
509
|
+
r.removeEventListener("open", a), r.removeEventListener("error", o), n(new Error("Datachannel open timeout"));
|
|
509
510
|
}, e);
|
|
510
|
-
r.addEventListener("open",
|
|
511
|
+
r.addEventListener("open", a), r.addEventListener("error", o);
|
|
511
512
|
});
|
|
512
513
|
}
|
|
513
514
|
class x {
|
|
514
515
|
/** @private */
|
|
515
|
-
constructor(e, t, n,
|
|
516
|
+
constructor(e, t, n, a, o, i) {
|
|
516
517
|
/**
|
|
517
518
|
* The underlying RTCPeerConnection.
|
|
518
519
|
* Exposed for advanced use cases like getting stats or accessing senders.
|
|
@@ -528,6 +529,7 @@ class x {
|
|
|
528
529
|
*/
|
|
529
530
|
l(this, "dataChannel");
|
|
530
531
|
l(this, "reassembler");
|
|
532
|
+
l(this, "ackPacingEnabled");
|
|
531
533
|
/**
|
|
532
534
|
* The data channel used for uploading video files (only available in file upload mode).
|
|
533
535
|
* Exposed for advanced use cases.
|
|
@@ -535,19 +537,21 @@ class x {
|
|
|
535
537
|
l(this, "uploadChannel");
|
|
536
538
|
l(this, "uploader");
|
|
537
539
|
l(this, "onComplete");
|
|
538
|
-
this.peerConnection = e, this._localStream = i == null ? void 0 : i.localStream, this.remoteStreamPromise = t, this.pipelineId = n, this.apiKey =
|
|
539
|
-
const
|
|
540
|
-
|
|
540
|
+
this.peerConnection = e, this._localStream = i == null ? void 0 : i.localStream, this.remoteStreamPromise = t, this.pipelineId = n, this.apiKey = a, this.dataChannel = o, this.reassembler = new N(), this.ackPacingEnabled = (i == null ? void 0 : i.ackPacingEnabled) === !0, this.uploadChannel = i == null ? void 0 : i.uploadChannel, this.onComplete = i == null ? void 0 : i.onComplete, this.dataChannel.binaryType = "arraybuffer";
|
|
541
|
+
const f = i == null ? void 0 : i.onData;
|
|
542
|
+
f && (this.dataChannel.addEventListener("message", (d) => {
|
|
541
543
|
try {
|
|
542
544
|
if (d.data instanceof ArrayBuffer) {
|
|
543
|
-
const { frameId: c, chunkIndex: s, totalChunks: y, payload: S } = A(d.data),
|
|
544
|
-
if (
|
|
545
|
-
const
|
|
546
|
-
|
|
545
|
+
const { frameId: c, chunkIndex: s, totalChunks: y, payload: S } = A(d.data), p = this.reassembler.processChunk(c, s, y, S);
|
|
546
|
+
if (p) {
|
|
547
|
+
const h = new TextDecoder("utf-8").decode(p), C = JSON.parse(h);
|
|
548
|
+
Promise.resolve(f(C)).finally(() => {
|
|
549
|
+
this.maybeSendAck(c);
|
|
550
|
+
});
|
|
547
551
|
}
|
|
548
552
|
} else {
|
|
549
553
|
const c = JSON.parse(d.data);
|
|
550
|
-
|
|
554
|
+
f(c);
|
|
551
555
|
}
|
|
552
556
|
} catch (c) {
|
|
553
557
|
console.error("[RFWebRTC] Failed to parse data channel message:", c);
|
|
@@ -558,6 +562,13 @@ class x {
|
|
|
558
562
|
this.reassembler.clear(), this.onComplete && this.onComplete();
|
|
559
563
|
});
|
|
560
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Send cumulative ACK after a frame is fully handled.
|
|
567
|
+
* Only used in batch mode (realtimeProcessing=false).
|
|
568
|
+
*/
|
|
569
|
+
maybeSendAck(e) {
|
|
570
|
+
this.ackPacingEnabled && this.dataChannel.readyState === "open" && this.dataChannel.send(JSON.stringify({ ack: e }));
|
|
571
|
+
}
|
|
561
572
|
/**
|
|
562
573
|
* Get the remote stream (processed video from Roboflow)
|
|
563
574
|
*
|
|
@@ -608,7 +619,7 @@ class x {
|
|
|
608
619
|
async cleanup() {
|
|
609
620
|
if (this.uploader && this.uploader.cancel(), this.reassembler.clear(), this.pipelineId && this.apiKey)
|
|
610
621
|
try {
|
|
611
|
-
await
|
|
622
|
+
await b.init({ apiKey: this.apiKey }).terminatePipeline({ pipelineId: this.pipelineId });
|
|
612
623
|
} catch (e) {
|
|
613
624
|
console.warn("[RFWebRTC] Failed to terminate pipeline:", e);
|
|
614
625
|
}
|
|
@@ -632,7 +643,7 @@ class x {
|
|
|
632
643
|
async startUpload(e, t) {
|
|
633
644
|
if (!this.uploadChannel)
|
|
634
645
|
throw new Error("No upload channel available. This connection was not created for file uploads.");
|
|
635
|
-
await
|
|
646
|
+
await ee(this.uploadChannel), this.uploader = new D(e, this.uploadChannel), await this.uploader.upload(t);
|
|
636
647
|
}
|
|
637
648
|
/**
|
|
638
649
|
* Cancel any ongoing file upload
|
|
@@ -698,74 +709,75 @@ async function F({
|
|
|
698
709
|
rtspUrl: e,
|
|
699
710
|
connector: t,
|
|
700
711
|
wrtcParams: n,
|
|
701
|
-
onData:
|
|
702
|
-
onComplete:
|
|
712
|
+
onData: a,
|
|
713
|
+
onComplete: o,
|
|
703
714
|
onFileUploadProgress: i,
|
|
704
|
-
options:
|
|
715
|
+
options: f = {},
|
|
705
716
|
hooks: d
|
|
706
717
|
}) {
|
|
707
|
-
var
|
|
718
|
+
var W;
|
|
708
719
|
if (!t || typeof t.connectWrtc != "function")
|
|
709
720
|
throw new Error("connector must have a connectWrtc method");
|
|
710
721
|
const c = !!e, s = !c && r instanceof File, y = !c && !s && r ? r : void 0, S = s ? r : void 0;
|
|
711
|
-
let
|
|
712
|
-
if ((!
|
|
722
|
+
let p = n.iceServers;
|
|
723
|
+
if ((!p || p.length === 0) && t.getIceServers)
|
|
713
724
|
try {
|
|
714
725
|
const g = await t.getIceServers();
|
|
715
|
-
g && g.length > 0 && (
|
|
726
|
+
g && g.length > 0 && (p = g, console.log("[RFWebRTC] Using TURN servers from connector"));
|
|
716
727
|
} catch (g) {
|
|
717
728
|
console.warn("[RFWebRTC] Failed to fetch TURN config, using defaults:", g);
|
|
718
729
|
}
|
|
719
|
-
const { pc: u, offer:
|
|
730
|
+
const { pc: u, offer: h, remoteStreamPromise: C, dataChannel: E, uploadChannel: R } = await X(
|
|
720
731
|
y,
|
|
721
732
|
S,
|
|
722
|
-
|
|
733
|
+
p,
|
|
723
734
|
e,
|
|
724
735
|
d
|
|
725
736
|
), v = {
|
|
726
737
|
...n,
|
|
727
|
-
iceServers:
|
|
738
|
+
iceServers: p,
|
|
728
739
|
realtimeProcessing: n.realtimeProcessing ?? !s,
|
|
729
740
|
rtspUrl: e
|
|
730
741
|
}, m = await t.connectWrtc(
|
|
731
|
-
{ sdp:
|
|
742
|
+
{ sdp: h.sdp, type: h.type },
|
|
732
743
|
v
|
|
733
744
|
), w = { sdp: m.sdp, type: m.type };
|
|
734
745
|
if (!(w != null && w.sdp) || !(w != null && w.type))
|
|
735
746
|
throw console.error("[RFWebRTC] Invalid answer from server:", m), new Error("connector.connectWrtc must return answer with sdp and type");
|
|
736
|
-
const U = ((
|
|
737
|
-
await u.setRemoteDescription(w), await new Promise((g,
|
|
747
|
+
const U = ((W = m == null ? void 0 : m.context) == null ? void 0 : W.pipeline_id) || null;
|
|
748
|
+
await u.setRemoteDescription(w), await new Promise((g, L) => {
|
|
738
749
|
const _ = () => {
|
|
739
|
-
u.connectionState === "connected" ? (u.removeEventListener("connectionstatechange", _), g()) : u.connectionState === "failed" && (u.removeEventListener("connectionstatechange", _),
|
|
750
|
+
u.connectionState === "connected" ? (u.removeEventListener("connectionstatechange", _), g()) : u.connectionState === "failed" && (u.removeEventListener("connectionstatechange", _), L(new Error("WebRTC connection failed")));
|
|
740
751
|
};
|
|
741
752
|
u.addEventListener("connectionstatechange", _), _(), setTimeout(() => {
|
|
742
|
-
u.removeEventListener("connectionstatechange", _),
|
|
753
|
+
u.removeEventListener("connectionstatechange", _), L(new Error("WebRTC connection timeout after 30s"));
|
|
743
754
|
}, 3e4);
|
|
744
|
-
}), y &&
|
|
745
|
-
const
|
|
755
|
+
}), y && f.disableInputStreamDownscaling !== !1 && await Y(u);
|
|
756
|
+
const T = t._apiKey || null, B = v.realtimeProcessing === !1, P = new x(
|
|
746
757
|
u,
|
|
747
758
|
C,
|
|
748
759
|
U,
|
|
760
|
+
T,
|
|
749
761
|
E,
|
|
750
|
-
b,
|
|
751
762
|
{
|
|
752
763
|
localStream: y,
|
|
753
764
|
uploadChannel: R,
|
|
754
|
-
onData:
|
|
755
|
-
onComplete:
|
|
765
|
+
onData: a,
|
|
766
|
+
onComplete: o,
|
|
767
|
+
ackPacingEnabled: B
|
|
756
768
|
}
|
|
757
769
|
);
|
|
758
|
-
return S && R &&
|
|
770
|
+
return S && R && P.startUpload(S, i).catch((g) => {
|
|
759
771
|
console.error("[RFWebRTC] Upload error:", g);
|
|
760
|
-
}),
|
|
772
|
+
}), P;
|
|
761
773
|
}
|
|
762
|
-
async function
|
|
774
|
+
async function te({
|
|
763
775
|
source: r,
|
|
764
776
|
connector: e,
|
|
765
777
|
wrtcParams: t,
|
|
766
778
|
onData: n,
|
|
767
|
-
options:
|
|
768
|
-
hooks:
|
|
779
|
+
options: a = {},
|
|
780
|
+
hooks: o
|
|
769
781
|
}) {
|
|
770
782
|
if (r instanceof File)
|
|
771
783
|
throw new Error("useStream requires a MediaStream. Use useVideoFile for File uploads.");
|
|
@@ -774,17 +786,17 @@ async function ee({
|
|
|
774
786
|
connector: e,
|
|
775
787
|
wrtcParams: t,
|
|
776
788
|
onData: n,
|
|
777
|
-
options:
|
|
778
|
-
hooks:
|
|
789
|
+
options: a,
|
|
790
|
+
hooks: o
|
|
779
791
|
});
|
|
780
792
|
}
|
|
781
|
-
async function
|
|
793
|
+
async function re({
|
|
782
794
|
file: r,
|
|
783
795
|
connector: e,
|
|
784
796
|
wrtcParams: t,
|
|
785
797
|
onData: n,
|
|
786
|
-
onUploadProgress:
|
|
787
|
-
onComplete:
|
|
798
|
+
onUploadProgress: a,
|
|
799
|
+
onComplete: o,
|
|
788
800
|
hooks: i
|
|
789
801
|
}) {
|
|
790
802
|
return F({
|
|
@@ -795,17 +807,17 @@ async function te({
|
|
|
795
807
|
realtimeProcessing: t.realtimeProcessing ?? !0
|
|
796
808
|
},
|
|
797
809
|
onData: n,
|
|
798
|
-
onComplete:
|
|
799
|
-
onFileUploadProgress:
|
|
810
|
+
onComplete: o,
|
|
811
|
+
onFileUploadProgress: a,
|
|
800
812
|
hooks: i
|
|
801
813
|
});
|
|
802
814
|
}
|
|
803
|
-
async function
|
|
815
|
+
async function ne({
|
|
804
816
|
rtspUrl: r,
|
|
805
817
|
connector: e,
|
|
806
818
|
wrtcParams: t,
|
|
807
819
|
onData: n,
|
|
808
|
-
hooks:
|
|
820
|
+
hooks: a
|
|
809
821
|
}) {
|
|
810
822
|
if (!r.startsWith("rtsp://") && !r.startsWith("rtsps://"))
|
|
811
823
|
throw new Error("Invalid RTSP URL: must start with rtsp:// or rtsps://");
|
|
@@ -814,23 +826,23 @@ async function re({
|
|
|
814
826
|
connector: e,
|
|
815
827
|
wrtcParams: t,
|
|
816
828
|
onData: n,
|
|
817
|
-
hooks:
|
|
829
|
+
hooks: a
|
|
818
830
|
});
|
|
819
831
|
}
|
|
820
|
-
const
|
|
832
|
+
const se = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
821
833
|
__proto__: null,
|
|
822
834
|
ChunkReassembler: N,
|
|
823
835
|
FileUploader: D,
|
|
824
836
|
RFWebRTCConnection: x,
|
|
825
837
|
parseBinaryHeader: A,
|
|
826
|
-
useRtspStream:
|
|
827
|
-
useStream:
|
|
828
|
-
useVideoFile:
|
|
838
|
+
useRtspStream: ne,
|
|
839
|
+
useStream: te,
|
|
840
|
+
useVideoFile: re
|
|
829
841
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
830
842
|
export {
|
|
831
|
-
|
|
832
|
-
|
|
843
|
+
b as InferenceHTTPClient,
|
|
844
|
+
ie as connectors,
|
|
833
845
|
oe as streams,
|
|
834
|
-
|
|
846
|
+
se as webrtc
|
|
835
847
|
};
|
|
836
848
|
//# sourceMappingURL=index.es.js.map
|