HLS 直播停止更新:播放清單沒刷新,還是新片段遺失?
比對媒體序號、檢查最新片段,分辨 CDN 快取與播放器復原問題。附可重複執行的 HTTP 測試。
直播畫面停住時,網頁和最上層的 .m3u8 網址仍可能回傳 200。光看這個狀態碼無法判斷原因:播放器可能一再收到同一份媒體播放清單,也可能已經在更新後的清單看到新片段,卻無法下載。兩種情況涉及的環節和修復方式不同。
以下示範如何留下最精簡、但足以定位問題的請求紀錄。只檢查自己擁有或獲授權檢查的串流;分享日誌之前,請移除帶簽章的查詢參數、Cookie、權杖、觀眾識別碼及 IP 位址。
*驗證方式——2026 年 9 月 17 日:*我們使用 Node.js 24.12.0 執行本機迴圈 HTTP 測試。/live.m3u8 前兩次回應完全相同:媒體序號為 100,列出片段 100–102;第三次推進至序號 101,列出 101–103。片段 102 回傳 200,而剛列出的片段 103 刻意回傳 404。這重現了兩種HTTP 層級的觀察結果:播放清單快照未變,以及清單已更新但新片段無法取得。測試提供的是文字標記,不是可解碼的影片。我們沒有測試實際播放、hls.js 重試行為、直播編碼器、CDN 或裝置重新連線。重現程式保存在專案的 scripts/test-live-hls-playlist-diagnosis.cjs。
先看媒體播放清單,不要只看主播放清單
多變體(主)播放清單描述可選的版本;所選影片、音訊或字幕軌的直播媒體播放清單,才列出目前可用的片段。主清單請求成功,不代表所選子清單有更新。兩者差異請見主清單與媒體清單指南。
重新載入播放器前,先開啟開發者工具並保留網路紀錄。找出實際使用的媒體播放清單請求、重新導向後的最終網址,以及後續的片段請求。可篩選 m3u8、ts、m4s 和實際片段路徑;需要操作清單時可參考 M3U8 開發者工具指南。
至少保存兩次播放清單的回應內容,不能只抄兩個狀態碼。每次記錄 #EXT-X-MEDIA-SEQUENCE、首尾片段 URI、#EXT-X-TARGETDURATION、是否出現 #EXT-X-ENDLIST、回應時間,以及若有提供的 Date、Age、Cache-Control、ETag 與 Last-Modified。有些標頭可能不存在;照實註記缺少即可,不要自行補值。
辨認兩類關鍵故障跡象
| 請求紀錄 | 能確定什麼 | 下一步檢查 |
|---|---|---|
| 清單請求出現 4xx/5xx 或網路錯誤 | 用戶端未取得可用清單 | 來源伺服器、CDN、授權、DNS 或連線 |
| 多次回應逐位元組相同,序號及最新 URI 未變 | 用戶端在這些回應中尚未發現新媒體 | 發佈時間、快取時間、來源與邊緣節點回應、播放器是否重新載入 |
| 序號及最新 URI 已推進,新片段卻回傳 404 | 清單可能比片段先發佈,或片段路徑有誤 | 封裝程式發佈順序、來源物件、CDN 傳播、網址解析 |
| 片段回傳 200,但畫面仍停住 | HTTP 可存取不代表能播放 | 回應內容、媒體時間戳記、解碼、緩衝、播放器錯誤 |
清單含 #EXT-X-ENDLIST | 該播放內容宣告不會再新增片段 | 確認活動是否真的已結束 |
單次清單未變,不能證明直播故障。正常直播清單在兩次發佈之間本來就可能相同;請依目標時長收集足夠的快照。同樣地,片段回傳 200 不代表影片可解碼:成功狀態下也可能收到 HTML 錯誤頁或不相容的媒體片段。
依直播清單的重載節奏判斷
RFC 8216 要求用戶端定期重新載入仍在更新的直播媒體清單。依照規範,清單有變化後,下次嘗試至少等待一個目標時長;清單沒有變化時,至少等待半個目標時長。伺服器發佈含新片段版本的時限則是另一組規則。若目標時長為八秒,不能只因用戶端沒有每秒重載,就認定它「卡住」。
這些是協定規則,不保證第三方 CDN 或應用程式都會正確運作。低延遲 HLS 可能使用阻塞式清單重載與部分片段;應依實際串流的機制分析,不要套用通用的固定輪詢間隔。Apple 另有阻塞式重載的說明。
一般滑動式直播視窗會依序移除舊片段 URI,#EXT-X-MEDIA-SEQUENCE 也隨之推進。長時間斷線後,序號跳躍可能表示播放器已落在可用視窗之後;但光靠序號無法得知解碼器是否恢復。片段可用性和播放時間必須分開確認。
一組受控的請求紀錄
測試連續回傳以下三份清單快照。它沒有等待真正的目標時長,因此只隔離了回應內容,沒有驗證時序是否符合規範。
| 請求 | HTTP | 媒體序號 | 列出的片段 | 最新片段狀態 |
|---|---|---|---|---|
| 第一次 | 200 | 100 | 100、101、102 | 102 → 200 |
| 第二次 | 200 | 100 | 100、101、102 | 回應未變 |
| 第三次 | 200 | 101 | 101、102、103 | 103 → 404 |
第二次只表示當時尚未宣告新片段。第三次證明清單其後推進,但剛宣告的物件在測試網址上無法取得。這兩項觀察單獨都不能證明真實播放器會如何恢復。它們的價值是讓編碼器或 CDN 負責人取得具體的第一筆失敗請求,而不只是「直播卡住了」。
分開蒐集來源、CDN 與播放器的證據
如果邊緣節點一直回傳舊清單,請在授權條件相同的情況下,比對來源伺服器與 CDN 上的同一份清單。記錄最終網址及快取標頭。偏高的 Age 可作為線索,但不能只憑一個標頭推斷整套快取政策,也不能假設每家 CDN 都以相同方式顯示狀態。不要把隨意加上查詢參數當成永久「修復」:簽章網址與快取鍵可能讓結果失真,甚至帶來風險。
如果清單有推進、片段卻不見了,請以媒體播放清單網址 為基準解析出該片段的確切 URI,並同時檢查回應狀態與內容。即使清單夠新,片段若先被宣告、後才可取得,仍可能讓播放停頓。RFC 8216 要求清單所列片段立即可用。檢查封裝程式的發佈順序,以及來源和 CDN 是否及時提供新物件。
如果清單和片段請求都成功,再檢查播放器。使用 hls.js 時,可記錄 LEVEL_LOADING、LEVEL_LOADED 或 LEVEL_UPDATED、FRAG_LOADING、FRAG_LOADED 與 ERROR 的詳細資料,包含錯誤是否為致命錯誤。其 API 區分清單載入失敗和片段載入失敗。原生 Safari 播放不一定觸發相同事件;應改用該瀏覽器的媒體診斷工具。若屬較廣泛的緩衝問題,請續看 HLS 緩衝診斷。
網路重新連線後要測什麼
針對每種支援的瀏覽器和真實裝置,記錄清單請求是否恢復、序號與最新 URI 是否推進、下一個片段是否成功,以及影片播放時間是否再次前進。短暫離線要測,也要測長到滑動視窗越過舊播放位置的離線情況。桌面瀏覽器縮成手機寬度,不能取代手機網路切換或背景媒體政策的測試。
不要在每次網路事件後都自動呼叫 video.play(),就宣稱「恢復成功」。使用者可能自行暫停,也可能受到瀏覽器政策阻擋;串流本身也可能仍提供舊資料。保留由使用者操作的播放入口;如果來源已載入卻無法開始播放,請參考 HLS 自動播放問題診斷。
有用的事故紀錄應包含最後一個正常媒體序號、第一次未更新或失敗的回應、片段確切狀態、快取標頭、瀏覽器及播放器版本,以及播放是否恢復。這些證據才能區分「CDN 仍送出舊視窗」與「播放器無法解碼新片段」。
參考資料
- RFC 8216:HTTP Live Streaming 的直播清單更新與用戶端重載
- Apple:直播播放清單的滑動視窗建構
- Apple:啟用低延遲 HTTP Live Streaming
- hls.js 事件參考
- hls.js 錯誤詳情參考
依序追蹤媒體播放清單和第一個新宣告的片段。證據在哪一步停止變化,就從那一步繼續查,不必只對著凍結畫面猜測。