实时音频流套接字卡在浏览器中
Posted
技术标签:
【中文标题】实时音频流套接字卡在浏览器中【英文标题】:live audio stream socket get stuck in browser 【发布时间】:2018-08-25 14:35:40 【问题描述】:我正在尝试设置一个可以收听多个(私人)流的页面。 不幸的是,我无法让它运行。我已经尝试过Using php to opening live audio stream on android,但由于某种原因,浏览器在加载脚本时卡住了。
请参阅下面的脚本以及工作主机的示例(请参阅http://icecast.omroep.nl/radio4-bb-mp3)
有大神能指教一下吗
Tnx 提前!
$host = "icecast.omroep.nl";
$port = 80;
$sub = "/radio4-bb-mp3";
$sock = fsockopen($host,$port, $errno, $errstr, 30);
if (!$sock)
throw new Exception("$errstr ($errno)");
header("Content-type: audio/mpeg");
header("Connection: close");
fputs($sock, "GET $sub HTTP/1\r\n");
fputs($sock, "Host: $host \r\n");
fputs($sock, "Accept: */*\r\n");
fputs($sock, "Icy-MetaData:1\r\n");
fputs($sock, "Connection: close\r\n\r\n");
fpassthru($sock);
fclose($sock);
【问题讨论】:
您为什么要这样做?通过 PHP 运行流会产生大量额外开销。为什么不直接重定向到流? @Brad 流每天都在变化,所以我想围绕它构建一些逻辑,以确保允许用户使用流。我想在我的 Sonos 上进行配置,但我不想每天都更改 URL @Brad 我确实可以重定向 URL,但它真的需要那么多开销吗?流媒体的数量不多,所以我不介意它从服务器中占用多少 为什么在没有理由的情况下增加复杂性和负载?只需使用 302 重定向。此外,如果您要代理原始文件,则应使用适当的 HTTP 客户端。您在此处的代码完全不符合规范,您将遇到无法运行的服务器。 【参考方案1】:以下 cmets 您正在寻找的解决方案是:
<?php
$host = "icecast.omroep.nl";
$sub = "/radio4-bb-mp3";
header("Location: http://$host$sub");
现在我将解释您的代码出了什么问题
标题有问题。您正在添加自己的标头和远程标头作为正文的一部分。
icecast.omroep.nl 标头
HTTP/1.0 200 OK
Content-Type: audio/mpeg
Date: Sat, 24 Mar 2018 16:01:23 GMT
icy-br:192
ice-audio-info: samplerate=48000;channels=2;bitrate=192
icy-br:192
icy-genre:Classical
icy-metadata:1
icy-name:NPO Radio4
icy-pub:0
icy-url:http://www.radio4.nl
Server: Icecast 2.4.0-kh8
Cache-Control: no-cache, no-store
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
Connection: Close
Expires: Mon, 26 Jul 1997 05:00:00 GMT
icy-metaint:16000
给定你的脚本 index.php
<?php
$host = "icecast.omroep.nl";
$port = 80;
$sub = "/radio4-bb-mp3";
$sock = fsockopen($host,$port, $errno, $errstr, 30);
if (!$sock)
throw new Exception("$errstr ($errno)");
fputs($sock, "GET $sub HTTP/1\r\n");
fputs($sock, "Host: $host \r\n");
fputs($sock, "Accept: */*\r\n");
fputs($sock, "Icy-MetaData:1\r\n");
fputs($sock, "Connection: close\r\n\r\n");
fpassthru($sock);
fclose($sock);
request.txt
GET /
[Blank line]
提供您的脚本
$ php -S 0.0.0.0:8000 index.php
您的脚本响应:
$ (nc 127.0.0.1 8000 < request.txt) | head -n 27
HTTP/0.9 200 OK
Date: Sat, 24 Mar 2018 16:01:23 +0000
Connection: close
X-Powered-By: PHP/7.1.14
Content-type: text/html; charset=UTF-8
HTTP/1.0 200 OK
Content-Type: audio/mpeg
Date: Sat, 24 Mar 2018 16:01:23 GMT
icy-br:192
ice-audio-info: samplerate=48000;channels=2;bitrate=192
icy-br:192
icy-genre:Classical
icy-metadata:1
icy-name:NPO Radio4
icy-pub:0
icy-url:http://www.radio4.nl
Server: Icecast 2.4.0-kh8
Cache-Control: no-cache, no-store
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
Connection: Close
Expires: Mon, 26 Jul 1997 05:00:00 GMT
icy-metaint:16000
PHP 正在添加自己的标头。
您需要处理从http://icecast.omroep.nl/radio4-bb-mp3 收到的标头并使用方法header()
返回它们,然后您可以执行fpassthru()
。
HTTP 使用新行将标头与正文分开:https://www.rfc-editor.org/rfc/rfc2616#section-6
[header]
CRLF
[body]
所以应该很容易逐行解析并调用header()
,直到找到CRLF
(空行)然后触发fpassthru()
。
【讨论】:
这是一个糟糕的解决方案。使用适当的 HTTP 客户端。手动解析来自上游服务器的响应会导致麻烦。这段代码已经不对所有响应状态进行任何处理,更不用说跟踪重定向等了。绝对没有理由使用纯套接字客户端连接到 Icecast 服务器。可以使用 cURL。 (虽然,一个更好的解决方案是首先重定向到流,正如我在我的 cmets 中所说的那样。) 我只是在解释@koots 在他的解决方案中面临的问题,我认为我们所有人都可以从中学习。我同意有更好的方法,但他的解决方案需要对 HTTP 协议有深入的了解。 不,它没有。事实上,试图超越表层是这里的全部问题。没有理由重新发明 HTTP 客户端,如果一开始没有这样做,就没有理由弄清楚如何从响应正文中确定响应标头。你对情况的解释很好,但你提供的解决方案是不够的,实施后只会导致更多的问题。 Icecast 客户经常犯这个错误……正确的参考答案应该有正确的解决方案。 如果@koots 想充当“代理”,我应该推荐安装guzzle 吗?他的解决方案与他的需求非常接近。我同意拥有 Guzzle 客户端会更理想,但也可以没有。 最低实现只是readfile()
... 不过,这是错误的解决方案。正确的解决方案是重定向到服务器。如果需要代理,正确的解决方案是让另一个 Icecast 实例处理它,以便可以在本地缓冲流。以上是关于实时音频流套接字卡在浏览器中的主要内容,如果未能解决你的问题,请参考以下文章