HTTP range, streaming, music and audio
Asked Answered
P

0

1

I have a website which I use to stream audio files. Mainly, MP3 & OGG. Since few months, I handle myself (PHP) the steaming part (before it was apache2). First I do a normal 200 OK response with sliced binary response of my multimedia audio files (for memory allocation). It's working fine, but I got the Infinity duration on all my audio. According to this question, I have updated yesterday the streaming part.

And now, I have one of the strangest bug I could imagine. My refactor of code works really fine with MP3 but not with OGG... Images, or zip download also works with the class above, and they both work fine as before.

Here is my Stream class.

<?php
class Stream extends Response
{
    protected $filepath;
    protected $delete;
    protected $range = ['from' => 0, 'to' => null];

    public function __construct($filePath, $delete = false, $range = NULL)
    {
        $this->delete = $delete;
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $filePath);
        $size = filesize($filePath);

        $this->headers['Content-Type'] = $mimeType;
        $this->headers['Content-Length'] = $size;
        $this->headers['Accept-Ranges'] = 'bytes';
        $this->headers['Content-Transfer-Encoding'] = 'binary';
        unset($finfo, $mimeType);

        $this->code = 200;
        $this->range['to'] = $size - 1;

        if ($range !== NULL) {
            if (preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/i', $range) === false) {
                $this->code = 416;
            } else {
                $ranges = explode(',', substr($range, 6));
                foreach ($ranges as $rangee) {
                    $parts = explode('-', $rangee);
                    $this->range['from'] = intval($parts[0]);
                    $this->range['to'] = intval($parts[1]);

                    if (empty($this->range['to'])) {
                        $this->range['to'] = $size - 1;
                    }
                    if ($this->range['from'] > $this->range['to'] || $this->range['to'] >= $size) {
                        $this->code = 416;
                    }
                }
                $this->code = 206;
            }

        }

        if ($this->code === 416) {
            $this->headers = ['Content-Range' => 'bytes */{' . $size . '}'];
        } elseif ($this->code === 206) {
            $this->headers['Content-Range'] = 'bytes {' . $this->range['from'] . '}-{' . $this->range['to'] . '}/{' . $size . '}';
        }

        $this->filepath = $filePath;
    }

    public function show()
    {
        http_response_code($this->code);

        foreach ($this->headers as $header => $value) {
            header($header . ': ' . $value);
        }

        $file = fopen($this->filepath, 'r');
        fseek($file, $this->range['from']);

        $interval = $this->range['to'] - $this->range['from'];
        $outputBufferInterval = 4 * 1000;
        
        if ($interval < $outputBufferInterval) {
            $outputBufferInterval = $interval;
        }

        ob_start();
        while ($interval > 0) {
            echo fread($file, $outputBufferInterval);
            $interval -= $outputBufferInterval;
            ob_flush();
        }
        fclose($file);
        ob_end_clean();
        
        if ($this->delete) {
            unlink($this->filepath);
        }
    }
}

I am little confused with HTTP_RANGE. Thank you,

Parada answered 7/12, 2016 at 9:35 Comment(3)
Why are you doing this in PHP instead of letting the server handle it? In any case, Ogg cannot be arbitrarily segmented like MP3 can. There may be a problem client-side, but it's unclear what the client is in this case. Just browsers?Bargeboard
Yes client is browsers. I can not handle CORS header, sessions, auths etc..., as I want and properly. That's why I have done it in PHP.Parada
You don't need PHP for that. Just configure your server appropriately. You can actually replace your entire PHP script with proxy_pass in an Nginx config. It'd be far more efficient this way.Bargeboard

© 2022 - 2024 — McMap. All rights reserved.