php - 流媒体 MP3 : iOS restarts HTML5 audio after 2 minutes

标签 php ios html html5-audio

我正在尝试流式传输 mp3 文件并通过 HTML5 音频标签播放它。

大约 2 分钟后,iOS 开始从头开始播放音频。我在 Safari @ iOS 11.4 上对此进行了测试。

下面是简化的代码:

文件:index.html

<!DOCTYPE html>
<html>
<body>
  <audio controls><source src="audio.php" type="audio/mpeg"></audio>
</body>
</html>

文件:audio.php

header('Content-Type: audio/mpeg');
header('Content-Disposition: inline; filename="audio.mp3"');
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile('audio.mp3');
  • 如果我直接使用 audio.mp3 文件,音频就可以工作
  • 在所有其他设备/平台(Mac、Windows 和 Android 上的所有浏览器)上一切正常。

这个设置有什么问题?
如何正确地将音频流式传输到 iOS?

谢谢!

最佳答案

我遇到了同样的问题

这篇文章帮我解决了问题

https://mobiforge.com/design-development/content-delivery-mobile-devices

问题出在一些必须设置才能在 IOS 上工作的 header 参数上

//insert file path
$file = 'insert_file_path';

//audio/mpeg for mp3 file
$mime_type = 'audio/mpeg';

if (is_file($file)) {
    header("Content-type: $mime_type");
    if (isset($_SERVER['HTTP_RANGE'])) { // do it for any device that supports byte-ranges not only iPhone
        rangeDownload($file);
    } else {
        header("Content-Length: " . filesize($file));
        readfile($file);
    }
}else {
    // file not exist 
    // some error...
}

function rangeDownload($file) {
    $fp = @fopen($file, 'rb');

    $size   = filesize($file); // File size
    $length = $size;           // Content length
    $start  = 0;               // Start byte
    $end    = $size - 1;       // End byte
    // Now that we've gotten so far without errors we send the accept range header
    /* At the moment we only support single ranges.
     * Multiple ranges requires some more work to ensure it works correctly
     * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
     *
     * Multirange support annouces itself with:
     * header('Accept-Ranges: bytes');
     *
     * Multirange content must be sent with multipart/byteranges mediatype,
     * (mediatype = mimetype)
     * as well as a boundry header to indicate the various chunks of data.
     */
    header("Accept-Ranges: 0-$length");
    // header('Accept-Ranges: bytes');
    // multipart/byteranges
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
    if (isset($_SERVER['HTTP_RANGE'])) {

        $c_start = $start;
        $c_end   = $end;
        // Extract the range string
        list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
        // Make sure the client hasn't sent us a multibyte range
        if (strpos($range, ',') !== false) {

            // (?) Shoud this be issued here, or should the first
            // range be used? Or should the header be ignored and
            // we output the whole content?
            header('HTTP/1.1 416 Requested Range Not Satisfiable');
            header("Content-Range: bytes $start-$end/$size");
            // (?) Echo some info to the client?
            exit;
        }
        // If the range starts with an '-' we start from the beginning
        // If not, we forward the file pointer
        // And make sure to get the end byte if spesified
        if ($range == '-') {
            // The n-number of the last bytes is requested
            $c_start = $size - substr($range, 1);
        }
        else {
            $range  = explode('-', $range);
            $c_start = $range[0];
            $c_end   = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
        }
        /* Check the range and make sure it's treated according to the specs.
         * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
         */
        // End bytes can not be larger than $end.
        $c_end = ($c_end > $end) ? $end : $c_end;
        // Validate the requested range and return an error if it's not correct.
        if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {

            header('HTTP/1.1 416 Requested Range Not Satisfiable');
            header("Content-Range: bytes $start-$end/$size");
            // (?) Echo some info to the client?
            exit;
        }
        $start  = $c_start;
        $end    = $c_end;
        $length = $end - $start + 1; // Calculate new content length
        fseek($fp, $start);
        header('HTTP/1.1 206 Partial Content');
    }
    // Notify the client the byte range we'll be outputting
    header("Content-Range: bytes $start-$end/$size");
    header("Content-Length: $length");

    // Start buffered download
    $buffer = 1024 * 8;
    while(!feof($fp) && ($p = ftell($fp)) <= $end) {
        if ($p + $buffer > $end) {
            // In case we're only outputtin a chunk, make sure we don't
            // read past the length
            $buffer = $end - $p + 1;
        }
        set_time_limit(0); // Reset time limit for big files
        echo fread($fp, $buffer);
        flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit.
    }
    fclose($fp);
}

关于php - 流媒体 MP3 : iOS restarts HTML5 audio after 2 minutes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51115674/

相关文章:

ios - 使用解码对象(: forKey:) to decode an object that conforms to a protocol

ios - Objective C 类找不到 Swift 协议(protocol)的定义

javascript - 在文本后保持相同的高度和宽度 ('' )

html - CSS 无法更改 div 类中的文本颜色

html - 添加样式后第一个 child 无法正常工作

javascript - 大尺寸图像在 jcrop 中无法正确裁剪

php - 将数据插入两个或多个表:

javascript - AngularJS - 触发器生成后下载 PDF

php - PHP 中的 UPDATE 语句需要知道是否选择了新文件

iphone - xcode 5 : What's the best way to go back and forth between top of editor and where you were before?