如何从Icecast 2.4.0-kh9服务器获取流媒体元数据
解决方案
1. 修正JSON API请求路径
你之前的curl命令路径错误,Icecast的status-json.xsl接口部署在服务器根路径,而非流路径下。正确的请求命令应该是:
curl https://servidor21.brlogic.com:7216/status-json.xsl
如果服务器配置正常,这个请求会返回包含所有流信息的JSON,你需要的「正在播放」元数据在icestats -> source -> title字段中。
如果仍返回「Could not parse XSLT」,说明服务器可能未启用该接口或缺失XSLT文件,这种情况下只能通过解析流媒体本身的ICY元数据获取信息。
2. 解析ICY流媒体元数据
既然已确认icy-metaint值为16000,说明该流确实携带元数据。在Flutter中可按以下步骤解析:
核心逻辑
- 向流地址发送请求时,添加
Icy-MetaData: 1请求头,告知服务器返回元数据。 - 读取响应流时,每读取16000字节音频数据后,会跟随一段元数据块:
- 元数据块第一个字节表示元数据长度(实际长度为该值×16)。
- 元数据内容格式为
StreamTitle='歌手名 - 歌曲名';StreamUrl='...';,提取StreamTitle字段即可。
Dart代码示例
import 'dart:convert'; import 'dart:io'; Future<String?> fetchNowPlaying() async { const url = 'https://servidor21.brlogic.com:7216/live'; const icyMetaint = 16000; try { var request = await HttpClient().getUrl(Uri.parse(url)); request.headers.add('Icy-MetaData', '1'); var response = await request.close(); await for (var chunk in response) { var remaining = chunk.length; var position = 0; while (remaining > 0) { // 读取完整音频块 if (remaining >= icyMetaint) { position += icyMetaint; remaining -= icyMetaint; } else { break; } // 读取元数据长度标识 if (remaining < 1) break; var metaLengthByte = chunk[position]; position += 1; remaining -= 1; var metaLength = metaLengthByte * 16; if (metaLength == 0 || remaining < metaLength) break; // 解析元数据内容 var metaBytes = chunk.sublist(position, position + metaLength); position += metaLength; remaining -= metaLength; var metaString = utf8.decode(metaBytes).trim(); var titleMatch = RegExp(r"StreamTitle='([^']+)'").firstMatch(metaString); if (titleMatch != null) { return titleMatch.group(1); } } } } catch (e) { print('获取元数据失败: $e'); } return null; }
注意事项
- 该逻辑需要持续监听流数据,元数据更新时会自动获取最新内容。
- 需处理网络异常、流中断等情况,避免应用崩溃。
- 建议将解析逻辑放在单独Isolate中执行,防止阻塞UI线程。
内容的提问来源于stack exchange,提问作者Alek
相关产品推荐
相关产品推荐

