為什麼 HLS 直播會越播越慢,以及「回到直播」按鈕應該跳到哪裡

分別測量播放清單邊緣、牆上時鐘延遲、播放器安全距離、過期清單和低延遲 HLS 行為,準確診斷 HLS 直播延遲。

兩位觀眾觀看同一場 HLS 直播時,可能處在不同位置,但兩台播放器都顯示「直播中」。進度列即使已經到達最右端,也可能落後訊號來源數秒。如果「回到直播」按鈕跳到最後一個已公布的瞬間,而不是播放器支援的直播同步點,它甚至會讓播放更不穩定。

第一步是不要再把延遲當成一個數字。需要分別看訊號來源時間、播放清單可用性、播放位置與播放清單邊緣的距離、播放器選取的安全延遲,以及最終顯示時間。請只測試自己擁有或獲准檢查的串流,並從分享的記錄中移除簽章 URL、Cookie、觀眾 ID、IP 位址和私人主機名稱。

*驗證方法 — 2026 年 9 月 23 日:*我們使用 Node.js 24.12.0 對一份合成媒體播放清單執行確定性計算。該播放清單包含五個 6 秒片段,EXT-X-PROGRAM-DATE-TIME 從 UTC 16:00:00 開始。已公布視窗在 16:00:30 結束,觀察時間為 16:00:32。媒體時間為 6 的播放位置落後播放清單邊緣 24 秒,落後測試清單牆上時鐘 26 秒。採用刻意設定的 12 秒安全延遲後,受控「回到直播」目標為媒體時間 18:落後播放清單邊緣 12 秒,落後測試清單時鐘 14 秒。這只驗證腳本的播放清單計算。它沒有測量編碼器、網路、CDN、瀏覽器媒體管線、裝置時鐘、真實播放或端到端服務目標。腳本位於 scripts/test-hls-live-latency-budget.cjs。

比較之前,先替三個位置準確命名

「直播邊緣」常被用來指不同位置。應在記錄和監控面板中為每項觀察使用不同名稱。

位置或測量值實用定義證據來源
播放清單邊緣目前向該用戶端公布的最新媒體結束位置媒體播放清單以及片段或部分片段長度
可拖曳終點媒體元素目前回報的最晚可拖曳時間軸位置video.seekable.end(...)
直播同步點播放器在邊緣之後考量安全策略選出的目標播放器 API 或明確的應用程式設定
播放位置距離播放清單或可拖曳邊緣減去目前播放位置同一時間軸上的 currentTime 和對應邊緣
牆上時鐘延遲觀察時間減去播放位置對應的估算節目時間可信時鐘和一致的節目日期對映
擷取到顯示延遲從訊號來源擷取到觀眾螢幕呈現同步的訊號來源與顯示測量

這些數值不一致並不矛盾。播放器可能只落後其快取播放清單兩秒,但該播放清單本身已經遠遠落後來源站。最新播放清單可以很接近訊號來源,而觀眾可能在 DVR 視窗內暫停了十分鐘。節目日期標籤能識別內容時間,卻不能單獨證明攝影機何時擷取了某一影格。

先檢查播放器時間軸

在點選「回到直播」前後,記錄全部 seekable 範圍、目前播放時間、緩衝範圍、長度、播放速率和就緒狀態。

function mediaSnapshot(video) {
  const copyRanges = ranges => Array.from(
    { length: ranges.length },
    (_, index) => ({ start: ranges.start(index), end: ranges.end(index) })
  );

  return {
    currentTime: video.currentTime,
    duration: video.duration,
    playbackRate: video.playbackRate,
    seekable: copyRanges(video.seekable),
    buffered: copyRanges(video.buffered),
    readyState: video.readyState,
  };
}

不要用 duration 取代目前直播邊緣。MDN 指出,直播媒體可能失去對過期內容的存取,而設定 currentTime 後,實際位置仍可能被調整到媒體支援的位置。如果存在多個可拖曳範圍,應全部記錄,不要假定最後一個範圍能代表所有軌道和呈現版本。

如果要求的位置已經離開直播視窗,請使用 HLS 拖曳和 DVR 診斷指南。只有在目前時間軸已經明確後,才開始診斷延遲。

為什麼一般 HLS 會落後最後一個已公布片段

直播用戶端需要保留足夠媒體,才能承受正常的播放清單重新載入和下載波動。RFC 8216 建議:對尚未結束的播放清單,開始一般播放時不要選擇起點距離尾端不足三個目標長度的片段,因為起得太靠後可能導致停頓。這是協定層級的安全建議,並不是每台播放器都會精確保持三個片段延遲的承諾。

片段產生、播放清單發布、從來源站傳播到 CDN、播放清單重新載入時機、物件下載、緩衝策略、解碼和算繪都會造成延遲。其中一些可以重疊,另一些則會累積。只改變播放器起點,無法消除媒體出現在播放清單之前已經花掉的時間。

層級用來隔離它的證據常見錯誤結論
擷取和編碼畫面內時間碼或獨立觀察到的訊號來源時間EXTINF 能說明擷取延遲
封裝和發布片段/部分片段完成時間及播放清單可用時間CDN 回應時間等於封裝時間
CDN 和快取Age、快取狀態、最終 URL、重複的播放清單本文HTTP 200 代表取得最新播放清單
播放器載入播放清單/片段要求時序和所選起點進度列右端就是訊號來源邊緣
緩衝和復原緩衝範圍、停頓、播放速率變化每一秒額外延遲都是刻意保留的安全餘量
解碼和算繪媒體事件加裝置層級測量只憑 currentTime 就能得到擷取到顯示延遲

先測量第一個尚未被證實的層級。如果連續多次要求的播放清單本文,在預期更新週期之外仍完全相同,應先診斷過期交付,再調整播放器。我們的過期播放清單與遺失片段指南提供了判斷路徑。

計算兩種延遲,而不是一種

不需要牆上時鐘中繼資料,就能算出播放位置與播放清單邊緣的距離:

播放位置距離 = 播放清單時間軸終點 - 目前播放位置

這有助於控制播放器,但無法說明播放清單邊緣本身有多舊。如果有一致的 EXT-X-PROGRAM-DATE-TIME 對映和可信時鐘,再估算第二部分:

播放清單邊緣年齡 = 觀察時間 - 播放清單邊緣對應的節目時間
估算牆上時鐘延遲 = 播放清單邊緣年齡 + 播放位置距離

我們的測試清單把 2 秒的播放清單邊緣年齡與 24 秒的播放位置距離分開,受控時間軸上的總和為 26 秒。這些數字是測試輸入和輸出,不是對 M3U8Online 或正式環境廣播服務的測量。

RFC 8216 將 EXT-X-PROGRAM-DATE-TIME 定義為片段第一個取樣與絕對日期時間之間的對映,同時提醒播放清單日期可以表示內容產生時間,也可以表示與播放無關的其他時間。發布延遲指標前,請驗證時間戳記的實際含義、時區處理、時鐘同步,以及變體和不連續點之間的對映一致性。

「回到直播」應跳到同步點,而不是數學終點

可用時,可靠的「回到直播」操作應使用播放器文件明確說明的直播同步點。在 hls.js 中,liveSyncPosition 是直播邊緣減去所設定的安全延遲;maxLatency 則描述播放器可以向前跳到該同步點的延遲門檻。因此,播放器 API 比從其他服務照搬的固定減法更可靠。

如果播放路徑沒有公開直播同步目標,請在目前可拖曳範圍內定義符合產品要求的目標,並在支援的裝置上驗證。不要簡單執行 currentTime = seekable.end(last),然後假定最後一個已公布瞬間已經可以下載和解碼。

按鈕流程應該:

  1. 擷取目前可拖曳範圍和播放器延遲值。
  2. 選擇文件明確的播放器同步點,或經過驗證、位於最新可拖曳終點之前的目標。
  3. 將目標限制在目前可拖曳範圍內。
  4. 只要求一次拖曳,不要與播放器內建的延遲控制器對抗。
  5. 記錄 seeking、seeked、結果 currentTime 以及操作後的第一批要求。
  6. 確認結果後再更新按鈕狀態。

在確定性測試清單中,所選目標仍落後播放清單邊緣 12 秒。跳到該位置後,模型牆上時鐘延遲從 26 秒降到 14 秒,並沒有變為零。這正是保留 12 秒安全延遲和 2 秒邊緣年齡的預期結果。

明確「直播中」標記代表什麼

「直播中」是需要書面規定容差的產品決策。它可以表示觀眾接近播放器目標、接近播放清單邊緣,或接近可信節目時鐘。這三種承諾並不相同。

介面狀態範例判斷條件使用者操作
直播中播放位置在直播同步點的驗證容差內無需操作
落後直播目前位置有效,但超出該容差提供「回到直播」
已暫停播放已經暫停,即使剛才仍在直播位置分別提供繼續播放和回到直播
正在重新加入播放器正在載入校正後的目標顯示進度,暫不宣稱直播中
無可靠時鐘已知邊緣距離,但不知道牆上時鐘延遲不要顯示憑空編出的精確延遲

請提供無障礙文字標籤,不要只用紅點。如果觀眾主動在 DVR 視窗內回看,不要自動把他們拉回前方,除非產品明確承諾低延遲觀看並清楚說明這種行為。

診斷播放過程中持續增加的延遲

如果播放器開始時接近目標,後來卻越來越落後,請把偏離開始的時間與以下觀察進行比對:

  • 播放清單重新載入遲到、內容不變,或來自非預期的舊快取。
  • 片段下載時間接近或超過媒體長度。
  • 緩衝復原時從較舊位置繼續,而不是直播同步點。
  • 追趕策略改變播放速率後,速率一直低於 1。
  • 行動裝置分頁進入背景或應用程式暫停後,一般載入停止。
  • 廣告時段、時間戳記不連續、軌道切換或變體切換改變了時間軸。
  • 應用程式狀態反覆把舊的 currentTime 寫回播放器。
  • 設定的最大延遲校正從未觸發,或與自訂程式碼衝突。

把播放清單、網路、播放器和媒體元素事件記錄在同一條單調時間軸上。如果串流反覆停頓,請先修復交付問題,再縮小緩衝;HLS 緩衝診斷會分別檢查傳輸量、片段可用性、解碼和播放器狀態。

低延遲 HLS 是一種端到端模式

不能透過替播放清單改名或加入一個查詢參數來啟用低延遲 HLS。Apple 文件把部分片段、伺服器控制、阻塞式播放清單重新載入、預先載入提示、呈現版本報告,以及特定伺服器/CDN 行為視為協同運作的組成部分。目前的編寫指南還對 Part Target Duration 和 PART-HOLD-BACK 提出限制。

應把編碼器或封裝器、來源站、CDN 快取行為、播放清單回應、播放器支援和備援路徑一起驗證。不支援低延遲功能的用戶端可能採用不同的要求模式;即使清單含有低延遲標籤,錯誤緩衝或快取播放清單要求的 CDN 也會抵消預期效益。

不要只根據 PART-TARGET 宣傳延遲數字。使用同步時鐘和支援的正式環境路徑,測量真實的訊號來源到顯示行為。未測試的瀏覽器和裝置必須標為未測試。

執行受控測試矩陣

對每條支援的播放路徑記錄:

  • 原生 HLS 與 JavaScript/MSE(適用時兩者都測)。
  • 標準直播與真實的低延遲 HLS 設定。
  • 冷啟動、正常穩定播放、回到直播、暫停/繼續、DVR 回看,以及停頓後復原。
  • 最新來源站回應、CDN 命中和刻意合成的舊播放清單測試。
  • 低位元率和高位元率變體,以及替代音訊和字幕。
  • 實體行動裝置上的前景播放和背景復原。
  • 在正式支援的桌上型電腦、手機、平板和電視產品上播放同一條獲准測試的串流。

縮小桌面視窗並不等於測試行動裝置背景策略或解碼器。應如實記錄缺少的硬體。簽章媒體 URL 和觀眾識別碼不得出現在螢幕截圖與錯誤報告中。

用證據報告延遲預算

可執行的報告可以寫成:「UTC 16:00:32 時,最新公布的節目時間為 16:00:30。播放位置對映到 16:00:06,因此播放清單邊緣年齡為 2 秒,播放位置距離為 24 秒。點選『回到直播』後,要求了媒體時間 18 的播放器同步點,並在該位置完成。」這樣,封裝、CDN 和播放器負責人就能看清每一部分延遲屬於哪個層級。

報告中應包含時鐘來源與同步方式、節目日期語意、播放清單要求和快取資料、播放清單邊緣、可拖曳範圍、目前位置、播放器直播同步和最大延遲設定、校正後的第一批要求、停頓與播放速率變化,以及裝置/播放器版本。如果時間戳記對映或時鐘未經驗證,就不要提供牆上時鐘延遲。

主要參考資料

請分別測量播放清單邊緣、邊緣年齡和播放位置距離,再讓「回到直播」跳到經過測試的同步點,而不是最後一個已公布瞬間。這樣既能保留安全策略,又能揭露過期交付,並防止介面承諾一個從未真正測量的延遲數字。