@torrent-tv/proxy 2.9.4 → 2.9.6
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/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/services/hls-session-manager.js +24 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 2.9.6
|
|
2
|
+
|
|
3
|
+
- **Fix**: `probeInputDurationSeconds` now returns as soon as ffmpeg prints the container header (`Duration:`) instead of letting `-f null -` decode the whole stream until the 8 s timeout. Transcode-session creation was wasting ~8.6 s per session on this redundant decode (the duration was already available from the header, and `playback-plan` had probed it moments earlier). Cuts session-creation latency from ~9.7 s to ~1 s.
|
|
4
|
+
- **New**: `GET /api/transcode-sessions/:id/progress` now includes `segmentDurationSec`, so the browser can show progress toward the first segment (the only thing it waits for before playback) instead of a percentage of the whole-file transcode.
|
|
5
|
+
|
|
6
|
+
## 2.9.5
|
|
7
|
+
|
|
8
|
+
- **Fix**: Segment files are now read with a 4 MB `highWaterMark` (`hls-session-manager.js` `getFileStream`) so the body is delivered in few, large chunks. On a busy ARM host the in-process WebTorrent hashing starves the Node event loop in bursts while the first segments are served; reading in fewer iterations cuts the time lost between chunks (the first segment previously transferred in ~79 × 43 KB reads spaced ~610 ms apart).
|
|
9
|
+
|
|
1
10
|
## 2.9.4
|
|
2
11
|
|
|
3
12
|
- **Chore**: Temporary `[net-debug]` instrumentation in `data-channel-handler.js` now splits transfer timing into `fetchMs` (waiting for the local route, incl. ffmpeg segment finalization), `ttfbMs` (time to first body chunk), `sendMs` (channel send duration) and `chunks`, to locate where early-segment latency is spent (transport vs segment production).
|
package/package.json
CHANGED
|
@@ -33,6 +33,11 @@ const DEFAULT_SESSION_TTL_MS = 120 * 1000;
|
|
|
33
33
|
const DEFAULT_STARTUP_WAIT_MS = 5_000;
|
|
34
34
|
const MICROSECONDS_PER_SECOND = 1_000_000;
|
|
35
35
|
const PROGRESS_LOG_INTERVAL_MS = 5_000;
|
|
36
|
+
// Read segment files in large blocks so the body is delivered to the data
|
|
37
|
+
// channel in few, big chunks. On a busy ARM host the in-process WebTorrent
|
|
38
|
+
// hashing starves the event loop in bursts, so fewer read iterations means
|
|
39
|
+
// far less time lost between chunks while serving the first segments.
|
|
40
|
+
const SEGMENT_READ_HIGH_WATER_MARK = 4 * 1024 * 1024;
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
43
|
* Resolve after a given number of milliseconds.
|
|
@@ -272,6 +277,17 @@ async function probeInputDurationSeconds(ffmpegBin, inputUrl) {
|
|
|
272
277
|
}, 8_000);
|
|
273
278
|
ffmpeg.stderr.on("data", (chunk) => {
|
|
274
279
|
stderr += String(chunk);
|
|
280
|
+
// ffmpeg prints the container header ("Duration:") almost immediately,
|
|
281
|
+
// long before it decodes anything. Bail as soon as we have it instead of
|
|
282
|
+
// letting `-f null -` decode the whole stream until the 8 s timeout.
|
|
283
|
+
const duration = parseFfmpegDurationSeconds(stderr);
|
|
284
|
+
if (duration != null) {
|
|
285
|
+
clearTimeout(timeoutId);
|
|
286
|
+
if (!ffmpeg.killed) {
|
|
287
|
+
ffmpeg.kill("SIGTERM");
|
|
288
|
+
}
|
|
289
|
+
finish(duration);
|
|
290
|
+
}
|
|
275
291
|
});
|
|
276
292
|
ffmpeg.on("error", () => {
|
|
277
293
|
clearTimeout(timeoutId);
|
|
@@ -899,9 +915,12 @@ export class HlsSessionManager {
|
|
|
899
915
|
const filePath = path.join(session.dirPath, fileName);
|
|
900
916
|
try {
|
|
901
917
|
await access(filePath);
|
|
918
|
+
const isPlaylist = fileName === PLAYLIST_FILE_NAME;
|
|
902
919
|
return {
|
|
903
920
|
kind: "file",
|
|
904
|
-
stream:
|
|
921
|
+
stream: isPlaylist
|
|
922
|
+
? createReadStream(filePath)
|
|
923
|
+
: createReadStream(filePath, { highWaterMark: SEGMENT_READ_HIGH_WATER_MARK }),
|
|
905
924
|
contentType:
|
|
906
925
|
fileName === PLAYLIST_FILE_NAME
|
|
907
926
|
? "application/vnd.apple.mpegurl"
|
|
@@ -975,6 +994,10 @@ export class HlsSessionManager {
|
|
|
975
994
|
remainingSeconds: session.progress.remainingSeconds,
|
|
976
995
|
warmupPercent,
|
|
977
996
|
warmupRemainingSeconds,
|
|
997
|
+
// Segment length, so the browser can show progress toward the FIRST
|
|
998
|
+
// segment (the only thing it waits for before playback starts) instead
|
|
999
|
+
// of a percentage of the whole-file transcode.
|
|
1000
|
+
segmentDurationSec: this.segmentDurationSec,
|
|
978
1001
|
speed: session.progress.speed,
|
|
979
1002
|
updatedAt: session.progress.updatedAt,
|
|
980
1003
|
error: session.state === "failed" ? session.lastError : ""
|