通过 PHP 流式传输时,Safari 中的音频持续时间总是返回无穷大

Posted

技术标签:

【中文标题】通过 PHP 流式传输时,Safari 中的音频持续时间总是返回无穷大【英文标题】:audio duration in Safari always returning infinity when streaming through PHP 【发布时间】:2019-04-07 09:59:39 【问题描述】:

由于某种原因,在 Safari(而不是其他主要浏览器)中,当我通过 PHP 通过 JavaScript 中的 Audio 上下文提供 MP3 时, MP3 始终返回为infinity

最近几天这个问题一直困扰着我,在阅读了几个链接(包括this 一个)以寻找解决方案后,我一点进展都没有。


我的代码

php

$path = "path/to/file.mp3";
$file = [
    "path"      => $path,
    "size"      => filesize($path),
    "bitrate"   => $bitrate
];

header("Accept-Ranges: bytes", false);
header("Content-Length: " . $file["size"], false);
header("Content-Type: audio/mpeg", false);

echo file_get_contents($file["path"]);

exit;

javascript

var audio = new Audio(url);
// returns infinite on Safari
// returns 312.27311 on Chrome and Firefox (which is correct)
console.log(audio.duration);

我还没有弄清楚为什么这个问题只出现在 Safari 中以及首先是什么导致它,所以如果有人有解决方案,将不胜感激!

干杯。

【问题讨论】:

Safari 有很多这样的问题。我在播放 .gif 广告时遇到了类似的问题,我记得我所做的只是将显示广告框架的 html 标记更改为 。在你的情况下,我会为此目的在 github.com 上搜索插件,只要 safari 问题没有修复。 【参考方案1】:

经过像你一样的大量调查,我终于弄明白了。

Safari 发送的第一个请求具有标头:

Range: bytes=0-1

“正确”响应是您的工作,以便 Safari 发送额外请求以获取文件的其余部分。

这是我的“正确”标题示例:

Content-Length: 2
Accept-Ranges: bytes
Content-Range: bytes 0-1/8469
(Make sure you set response status to 206!)
(8469 is the Content-Length of the entire file)

之后发生的事情有点神奇 - Safari 发送具有此标头的后续请求:

Range: bytes=0-8468

您应该像使用这些标题一样“正确”响应:

Content-Length: 8469
Accept-Ranges: bytes
Content-Range: bytes 0-8468/8469
(Again, status 206!)

我希望这可以为您解决问题,因为我花了很多时间寻找无济于事。我最终意识到我需要调整我的服务器来处理存在 Range 标头的请求。

我使用此提交来帮助我理解“正确”响应是什么:https://github.com/jooby-project/jooby/commit/142a933a31b9d8742714ecd38475d90e563314f7

【讨论】:

这将如何在 PHP 中实现?我无法响应 206 否则音频根本无法播放。【参考方案2】:

由于这个帖子首先在谷歌弹出,请允许我分享我的经验。

像许多人一样,我通过 php 页面生成 mp3,主要是为了“隐藏”mp3 的真实链接。为此,Safari 相当烦人。简而言之,Safari 将声音视为“直播”,最终拥有“无限”持续时间。详情this post解释的很好。

那该怎么办?您必须在生成声音的 php 页面的标题上设置条件(如@brianarpie 所述)。这是我的 php-generating-mp3 页面:

<?php
// first, you need this function :
function serveFilePartial($fileName, $fileTitle = null, $contentType = 'application/octet-stream')
// the code of this can be found here : https://github.com/pomle/php-serveFilePartial/blob/master/ServeFilePartial.inc.php

$link_of_your_mp3 = "var/my_folder/my_music.mp3"; // this is not an URL, but an absolute path
// and we call the function :
serveFilePartial($link_of_your_mp3, null, 'audio/mpeg');

?>

.. 就是这样!此函数将根据网络浏览器的要求生成正确的标题。

当然,您已经对链接、变量等进行了所有检查以保护页面。请注意,我的示例是 mp3,因此我必须使用“audio/mpeg”调用该函数。如果你输出不同的文件格式,你将不得不适应函数的内容类型。

【讨论】:

以上是关于通过 PHP 流式传输时,Safari 中的音频持续时间总是返回无穷大的主要内容,如果未能解决你的问题,请参考以下文章

具有不同长度的音频文件的 HTTP 实时流式传输

如何实时流式传输音频文件

下载数据时如何流式传输音频?

将音频从 Node.js 服务器流式传输到 HTML5 <audio> 标签

Qt 通过 TCP 套接字实时流式传输音频

通过网络将系统音频流式传输到 Web 浏览器 (javascript)