V46: FILL 48->96 (cushion ~512ms) chong stall ~500ms (u2 deficit 723ms) + instrument 3 lop (wl_gap/main_in_gap/pump_hb)
This commit is contained in:
@@ -1135,9 +1135,18 @@ async def ws_fx_realtime(websocket: WebSocket, session_id: str):
|
||||
_pf.write("%d pump_start\n" % int(_time.time() * 1000))
|
||||
_last_lat = None
|
||||
_last_proc = None
|
||||
_hb_last = _time.time()
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
# V46: heartbeat — mỗi ~100ms; gap giữa 2 pump_hb liên tiếp
|
||||
# > 300ms = event loop engine bị freeze (cause toàn cục stall
|
||||
# cả 2 session — bridge idle chờ input). Phân biệt với client
|
||||
# stall (wl_gap/main_in_gap) và bridge stall (pump_gap).
|
||||
_hb_now = _time.time()
|
||||
if _pf is not None and (_hb_now - _hb_last) >= 0.1:
|
||||
_hb_last = _hb_now
|
||||
_pf.write("%d pump_hb" % int(_hb_now * 1000) + chr(10))
|
||||
sess.flush_input_stale() # input lẻ kẹt trong pending → publish
|
||||
_lats = sess.get_latencies()
|
||||
_total = sum(_lats.values()) if _lats else 0
|
||||
|
||||
+12
-1
@@ -303,6 +303,7 @@ window.__fxRtQueueLen = function () {
|
||||
// V28: do jank — play_start timestamp; play_rAF / play_first_audio log delta.
|
||||
let _dbgPlayStartMs = 0;
|
||||
let _dbgLastClearMs = 0;
|
||||
let _inLastIn = 0; // V46: thời điểm 'in' handler cuối — đo gián đoạn main thread
|
||||
let _dbgFirstAudioPending = false;
|
||||
let _dbgFirstAudiblePending = false;
|
||||
// V40: real PDC — freeze playhead theo latency đo được (fx_play_first self-calib).
|
||||
@@ -2074,6 +2075,14 @@ async function fxRtStart() {
|
||||
return;
|
||||
}
|
||||
if (d.type !== 'in') return;
|
||||
// V46: main_in_gap — main thread nhận 'in' cách >30ms = main thread bị
|
||||
// block (rAF/React/GC) → input delivery đứt → engine đói → wobble. Kết
|
||||
// hợp wl_gap (audio thread) + pump_hb (engine) phân biệt lớp gây stall.
|
||||
const _inNow = performance.now();
|
||||
if (_inLastIn && (_inNow - _inLastIn) > 30) {
|
||||
try { _dbgLog('main_in_gap', Math.round(_inNow - _inLastIn)); } catch (e) {}
|
||||
}
|
||||
_inLastIn = _inNow;
|
||||
// Gửi NGAY, không pace setTimeout: input pacing = đồng hồ audio worklet
|
||||
// (1 frame/21.33ms), không phải timer main-thread. Timer bận/trễ → input
|
||||
// gửi trễ → engine/bridge chỉ sản xuất output khi có input → cushion cạn
|
||||
@@ -2165,7 +2174,9 @@ function fxRtStop(silent) {
|
||||
// ≈ 1792) + FILL buffer 48 block (12288) = 55 block ≈ 14080 (~293ms @48k). Giữ
|
||||
// đồng bộ với sf-fx-realtime.js. FX_RT_START_EST_MS: ước lượng khởi đầu khi
|
||||
// chưa có phép đo (fx_play_first) — dùng cho freeze playhead thay V39 0.31s.
|
||||
const FX_RT_ROUNDTRIP_SAMPLES = 14080;
|
||||
// V46: FILL 48→96 → RTT = 7 + 96 = 103 block ≈ 26368 (~549ms @48k). Đồng bộ
|
||||
// sf-fx-realtime.js V46 (hấp thụ stall ~500ms u2 08:16:44.8).
|
||||
const FX_RT_ROUNDTRIP_SAMPLES = 26368;
|
||||
const FX_RT_START_EST_MS = 450;
|
||||
// G3: anchor processed — playhead = startOffset + (processed - anchor - latency)/sr
|
||||
// (da tru latency -> bam vi tri mau NGHE DUOC; pre-roll tu giu tai startOffset —
|
||||
|
||||
@@ -29,10 +29,10 @@ class SfFxRealtimeProcessor extends AudioWorkletProcessor {
|
||||
super();
|
||||
this.BLOCK = 256; // FXRT_BLOCK
|
||||
this.BURST = 4; // số block gom 1 frame (bridge batch)
|
||||
this.FILL = 48; // V45: 48 block ~256ms @48k: hấp thụ stall OS-level ~200ms (V44 21:17:37.9: engine pump 198ms + main 196ms cùng lúc → u=2 underrun → lag 20-30s). PDC 14080 = (7+48)*256 (fxRtApplyPdc). V44 24 -> cushion 128ms < stall 196ms -> underrun. V45 48 -> cushion 256ms (margin ~60ms).
|
||||
this.FILL = 96; // V46: 96 block ~512ms @48k: hấp thụ stall ~500ms (u2 08:16:44.8: pump deficit 723ms, event gap 507ms → V45 cushion 256ms cạn → silence ~500ms → wobble). PDC 26368 = (7+96)*256 (fxRtApplyPdc). V45 48 -> cushion 256ms < deficit 723ms -> underrun. V46 96 -> cushion ~512ms (margin ~200ms vs event 507ms; deficit cluster vẫn có thể underrun ngắn — chấp nhận, content jump giữ policy V24).
|
||||
this.RESUME_FILL = 24; // V26: re-buffer khi resume SAU STOP (flush_for_stop) — 16 block ~85ms (V43: = FILL) → play kế tiếp bắt đầu nhanh; underrun-stall vẫn dùng FILL (crackle/wobble).
|
||||
this.resumeFill = this.FILL; // mức re-buffer khi resume sau flush — stop: RESUME_FILL, underrun-stall: FILL
|
||||
this.CAP = 56; // V45: = FILL+8: cap queue chặn overflow (~300ms)
|
||||
this.CAP = 104; // V46: = FILL+8: cap queue chặn overflow (~550ms)
|
||||
this.HOLD_FADE = 4; // 4 block ~21ms: fade 1→0 sau HOLD hết (hết click cắt cứng)
|
||||
this.holdFadeLeft = 0; // mẫu còn lại của fade-out khi underrun
|
||||
this.silenced = false; // đã fade về 0 → im lặng; resume phải fade-in, không hold lại
|
||||
@@ -171,6 +171,8 @@ class SfFxRealtimeProcessor extends AudioWorkletProcessor {
|
||||
this.dbgInFirst = false;
|
||||
this.dbgOutFirst = false;
|
||||
this.dbgPlayFirst = false;
|
||||
this._wlLast = 0; // V46: thời điểm process() lần trước — đo gián đoạn audio thread
|
||||
this._wlGapAt = 0; // V46: rate-limit wl_gap 1/s
|
||||
}
|
||||
process(inputs, outputs) {
|
||||
const input = inputs[0];
|
||||
@@ -179,6 +181,17 @@ class SfFxRealtimeProcessor extends AudioWorkletProcessor {
|
||||
const outL = output[0];
|
||||
const outR = output[1];
|
||||
|
||||
// V46: wl_gap — audio thread bị gián đoạn (process() cách >30ms, thường do
|
||||
// main thread block chia sẻ buffer/GC) → dbg log. Rate-limit 1/s.
|
||||
if (this._wlLast > 0) {
|
||||
const _wlGap = currentTime - this._wlLast;
|
||||
if (_wlGap > 0.030 && (currentTime - this._wlGapAt) > 1.0) {
|
||||
this._wlGapAt = currentTime;
|
||||
this.port.postMessage({ type: 'dbg', tag: 'wl_gap', t: Math.round(currentTime * 1000), g: Math.round(_wlGap * 1000) });
|
||||
}
|
||||
}
|
||||
this._wlLast = currentTime;
|
||||
|
||||
// Góp input thành burst 4 block (1024 mẫu) → gửi main thread
|
||||
// (transferable buffer). Main thread tách 4 WS frame → bridge batch 4.
|
||||
if (input && input[0]) {
|
||||
|
||||
Reference in New Issue
Block a user