用于Windows Chrome(以及可能许多其他浏览器),此代码可用于在audio
元素中使用MP3:
/**
*
* @param string $filename
* @return IlluminateHttpResponse|IlluminateContractsRoutingResponseFactory
*/
public function getMp3($filename) {
$fileContents = Storage::disk(AppHelpersCoachingCallsHelper::DISK)->get($filename);
$fileSize = Storage::disk(AppHelpersCoachingCallsHelper::DISK)->size($filename);
$shortlen = $fileSize - 1;
$headers = [
'Accept-Ranges' => 'bytes',
'Content-Range' => 'bytes 0-' . $shortlen . '/' . $fileSize,
'Content-Type' => "audio/mpeg"
];
Log::debug('$headers=' . json_encode($headers));
$response = response($fileContents, 200, $headers);
return $response;
}
但是,当我使用iPhone浏览到同一页面时,MP3文件不会显示总持续时间,当我播放它时,它说"实时广播"。
我试图遵循这个问题的各种答案的建议(html5< audio> safari live vielcast vs vs而不是)和我读过的其他文章,但似乎没有任何作用。
>无论我如何更改标头,MP3似乎都按照Windows的需求起作用,并且在iOS上工作。
我如何调试我做错了什么?
这是html:
<audio controls preload="auto">
<source src="{{$coachingCall->getMp3Url()}}" type="audio/mpeg"/>
<p>Your browser doesnt support embedded HTML5 audio. Here is a <a href="{{$coachingCall->getMp3Url()}}">link to the audio</a> instead.</p>
</audio>
mp3文件没有时间戳,因此没有可以提前知道的固有长度。Chrome只是基于文件开头和文件的字节大小的比特率猜测。它真的不知道。
有些球员不打扰猜测。
此外,iOS上的所有浏览器均在引擎盖下进行,这要归功于Apple的一些极为限制的政策。因此,iOS上的Chrome实际上只是Safari Web视图的包装器。
哇,这是一个很难解决的问题。(花了我几天。)
我了解到,这不仅仅是遇到问题的iOS:Mac上的Safari也没有工作。
现在,我认为一切都可以在我测试过的每个浏览器上都起作用。
我真的很高兴我找到了这个示例。
这是我的答案:
/**
*
* @param string $disk
* @param string $filename
* @return IlluminateHttpResponse|IlluminateContractsRoutingResponseFactory|SymfonyComponentHttpFoundationStreamedResponse
*/
public static function getMediaFile($disk, $filename) {
$rangeHeader = request()->header('Range');
$fileContents = Storage::disk($disk)->get($filename);
$fullFilePath = Storage::disk($disk)->path($filename); //https://stackoverflow.com/a/49532280/470749
$headers = ['Content-Type' => Storage::disk($disk)->mimeType($fullFilePath)];
if ($rangeHeader) {
return self::getResponseStream($disk, $fullFilePath, $fileContents, $rangeHeader, $headers);
} else {
$httpStatusCode = 200;
return response($fileContents, $httpStatusCode, $headers);
}
}
/**
*
* @param string $disk
* @param string $fullFilePath
* @param string $fileContents
* @param string $rangeRequestHeader
* @param array $responseHeaders
* @return SymfonyComponentHttpFoundationStreamedResponse
*/
public static function getResponseStream($disk, $fullFilePath, $fileContents, $rangeRequestHeader, $responseHeaders) {
$stream = Storage::disk($disk)->readStream($fullFilePath);
$fileSize = strlen($fileContents);
$fileSizeMinusOneByte = $fileSize - 1; //because it is 0-indexed. https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
list($param, $rangeHeader) = explode('=', $rangeRequestHeader);
if (strtolower(trim($param)) !== 'bytes') {
abort(400, "Invalid byte range request"); //Note, this is not how https://stackoverflow.com/a/29997555/470749 did it
}
list($from, $to) = explode('-', $rangeHeader);
if ($from === '') {
$end = $fileSizeMinusOneByte;
$start = $end - intval($from);
} elseif ($to === '') {
$start = intval($from);
$end = $fileSizeMinusOneByte;
} else {
$start = intval($from);
$end = intval($to);
}
$length = $end - $start + 1;
$httpStatusCode = 206;
$responseHeaders['Content-Range'] = sprintf('bytes %d-%d/%d', $start, $end, $fileSize);
$responseStream = response()->stream(function() use ($stream, $start, $length) {
fseek($stream, $start, SEEK_SET);
echo fread($stream, $length);
fclose($stream);
}, $httpStatusCode, $responseHeaders);
return $responseStream;
}
我无法发表评论,因为我刚刚制作了我的帐户,所以...补充瑞安的
刚刚发现您可以节省一些加载时间来删除
$fileContents = Storage::disk($disk)->get($filename);
并用
代替它$fileSize = Storage::disk($disk)->size($filename);
将大小直接传递到getResponsestream函数,而不是将整个内容下载到变量中,然后测量长度。
谢谢你,瑞安,为我省下了很多宝贵的时光。