簡體   English   中英

使用 Javascript 和 Web 音頻 API 流式傳輸 Icecast 音頻和元數據

[英]Streaming Icecast Audio & Metadata with Javascript and the Web Audio API

我一直在試圖找出實現我已經有一段時間的想法的 go 的最佳方法。

目前,我有一個無線電掃描儀的 icecast mp3 stream,其中“正在播放”的元數據會根據掃描儀登陸的頻道實時更新。 當使用 VLC 等專用媒體播放器時,元數據與接收到的音頻完美對齊,並且它的功能完全符合我的要求 - 本質上是一個遠程無線電掃描儀。 我想通過網頁實現類似的東西,表面上這似乎是一個簡單的任務。

如果我想做的只是 stream 音頻,那么使用簡單的<audio>標簽就足夠了。 但是,HTML5 音頻播放器沒有嵌入流內元數據的概念,該元數據與 mp3 音頻數據一起進行了 icecast 編碼。 雖然我可以從 icecast 服務器狀態 json 查詢當前“正在播放”的元數據,但由於客戶端和服務器端緩沖,以這種方式完成時,音頻和元數據之間可能會有超過 20 秒的延遲。 在某些情況下,當掃描儀每秒更改其“正在播放”的元數據時,這完全不適合我的應用程序。

有一個非常有趣的 Node.JS 解決方案,它是在考慮到這個確切目標的情況下開發的——無線電掃描儀應用程序中的實時元數據: icecast-metadata-js 這表明確實可以處理來自單個 icecast stream 的音頻和元數據。 現場演示尤其令人印象深刻: https://eshaz.github.io/icecast-metadata-js/

但是,我正在尋找一種無需安裝 Node.JS 即可完全在客戶端運行的解決方案,而且這似乎應該是相對微不足道的。

今天搜索了一天的大部分時間后,似乎在本網站和其他地方提出了幾個類似的問題,但沒有任何連貫的、布局合理的答案或建議。 From what I've been able to gather so far, I believe my solution is to use a Javascript streaming function (such as fetch ) to pull the raw mp3 & metadata from the icecast server, playing the audio via Web Audio API and handling the元數據塊到達時。 如下圖所示:

數據處理框圖

我想知道是否有人通過 Web 音頻 API 播放 mp3 流有任何好的閱讀和/或示例。 在大多數 JS 方面,我仍然是一個相對新手,但我了解了 API 的基本概念以及它如何處理音頻數據。 我正在努力實現的正確方法是:a)實時處理來自 mp3 stream 的數據,以及 b)檢測嵌入在 stream 中的元數據塊並相應地處理這些塊。

如果這是一個冗長的問題,我深表歉意,但我想提供足夠的背景故事來解釋為什么我想以我的具體方式向 go 講述事情。

提前感謝您的建議和幫助!

很高興您找到了我的圖書館icecast-metadata-js 這個庫實際上可以在客戶端和 NodeJS 中使用,現場演示的所有源代碼,它完全在客戶端運行:在存儲庫中: https://github.com/eshaz/icecast-metadata- js/tree/master/src/demo . 演示中的流沒有改變,只是服務器端的普通 Icecast 流。

您在圖表中的內容基本上是正確的。 ICY 元數據交織在實際的 MP3“流”數據中。 ICY 元數據更新發生的元數據間隔或頻率可以在 Icecast 服務器配置 XML 中配置。 此外,這可能取決於您的來源向 Icecast 發送元數據更新的頻率/准確度。 在我的演示頁面上,警察掃描儀中使用的軟件幾乎與音頻同步更新。

通常,默認元數據間隔為 16,000 字節,這意味着每 16,000 個 stream (mp3) 字節,將從 Icecast 發送元數據更新。 元數據更新總是包含一個長度字節。 如果長度字節大於0,則元數據更新的長度為元數據長度字節*16。

ICY 元數據是一串由分號分隔的 key='value' 對。 元數據更新中任何未使用的長度都是 null 填充的。

"StreamTitle='The Stream Title';StreamUrl='https://example.com';\0\0\0\0\0\0"

read [metadataInterval bytes]        -> Stream data
read [1 byte]                        -> Metadata Length
if [Metadata Length > 0]
   read [Metadata Length * 16 bytes] -> Metadata

字節長度 響應數據 行動
ICY 元數據間隔 stream數據 發送到您的音頻解碼器
1 元數據長度字節 用於確定元數據字符串的長度(不發送到音頻解碼器)
元數據長度 * 16 元數據字符串 解碼並更新您的“正在播放”(不要發送到音頻解碼器)

對 Icecast 服務器的初始GET請求需要包含Icy-MetaInt: 1 header,它告訴 Icecast 提供交錯的元數據。 響應 header 將包含 ICY 元數據間隔Icy-MetaInt ,應捕獲(如果可能)並用於確定元數據間隔。

在演示中,我使用客戶端獲取 API 來發出 GET 請求,並將響應數據提供給IcecastReadableStream的一個實例,該實例將 stream 和元數據分開,並通過回調使每個可用。 我正在使用媒體源 API 播放 stream 數據,並獲取時序數據以正確同步元數據更新。

這是讀取 ICY 元數據所需的最低 CORS 配置:

Access-Control-Allow-Origin: '*' // this can be scoped further down to your domain also
Access-Control-Allow-Methods: 'GET, OPTIONS'
Access-Control-Allow-Headers: 'Content-Type, Icy-Metadata'

如果需要, icecast-metadata-js可以檢測 ICY 元數據間隔,但最好允許客戶端使用此額外的 CORS 配置從 header 讀取它:

Access-Control-Expose-Headers: 'Icy-MetaInt'

此外,我計划發布一個新功能(在我完成 Ogg 元數據之后),它封裝了fetch api 邏輯,這樣用戶所需要做的就是提供一個 Icecast 端點,並取回音頻/元數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM