Можно ли перевести интернет-радио с помощью PHP?(Нужен PHP-гуру) - PullRequest
3 голосов
/ 03 ноября 2011

Можно ли перевести интернет-радио с помощью PHP?

Радио доступно на порту 8000. Я хотел бы использовать свой веб-сервер и «передавать» радиопоток на порт 80.

Возможно ли это?

Я уже гуглил его и нашел http://support.spacialnet.com/forums/viewtopic.php?f=13&t=16858&start=15 , но он не работает для меня. На самом деле он работает. Прежде чем просто забыть изменить MIME-тип потока.

Я настроил решение по ранее упомянутому URL (http://support.spacialnet.com/forums/viewtopic.php?f=13&t=16858&start=15). Сейчас оно работает, но поток всегда прерывается примерно через 8 минут прослушивания. Любая подсказка, почему? (Максимальное время выполнения сервера установлено на 30 секунд). Я тестировал разные потоки с разными битрейтами, но каждый раз он ведет себя одинаково. Любая помощь?

Ответы [ 3 ]

2 голосов
/ 03 ноября 2011

Я не должен тебе этого говорить.Но с чисто академической точки зрения вы, вероятно, захотите использовать fpassthru .Это позволит вам загрузить файл (в данном случае поток) и выгрузить его немедленно и за столько времени, сколько потребуется.(Для потока это навсегда.)

Что касается конкретных деталей, это, вероятно, будет очень похоже на предоставленную вами ссылку.

Возможная проблема: максимальное время выполнения скриптаможет стать проблемой.Я не уверен.Если это так, вы всегда можете увеличить его до того, чего вы вряд ли достигнете за данное прослушивание.

Наконец.Не делай этого ...

1 голос
/ 01 декабря 2011

Это определенно технически возможно.Я бы попробовал использовать wireshark, чтобы посмотреть на пакеты.На 8-минутной отметке может отсутствовать что-то, что является собственностью SHOUTcast.

Вы также можете попробовать немного буферизовать его.Может быть, поток глохнет?

1 голос
/ 01 декабря 2011

Я, вероятно, не должен был отвечать на этот вопрос, но у меня было немного свободного времени на работе и я хотел немного поиграть с сокетами.

Вот мой класс, он не очень хорошо протестирован (ну, он работал при первом запуске, что подозрительно) и может содержать ошибки, но он может дать вам несколько полезных идей.Он удаляет заголовки ICY * в качестве примера, который вы опубликовали, но это можно легко изменить.

Я проверил его на плеере Ubuntu Totem, и он хорошо играл в течение 10 минут, прежде чем я остановил его, но, возможно, мне просто повезло (: По крайней мере, 8 минут, похоже, не магическое число.

<?php

ob_start();

class RadioProxy {
    CONST STREAM_content_type='audio/aac';
    CONST STREAM_timeout=1.5;

    CONST HTTP_response_header_first='/\s200\s/';
    CONST HTTP_response_header_pattern='/^[a-z\-]+:/i';
    CONST HTTP_max_line_length=1024;

    CONST HTTP_delim="\r\n";
    CONST HTTP_max_response_headers=40;
    CONST ERROR_max=5;
    CONST ERROR_interval=120;
    CONST ERROR_usleep=300000;


    private $server_name, $server_port;
    private $HTTP_headers;
    private $STREAM = NULL;
    private $STREAM_errors = array();
    private $TIMEOUT_seconds, $TIMEOUT_microseconds;

    public function __construct($server_name, $server_port, $filename='') {
        self::STREAM_set_headers();
        $this->server_name = $server_name;
        $this->server_port = $server_port;
        $this->HTTP_headers = $this->HTTP_generate_headers($filename);
        $this->connect();
    }

    private function connect() {
        $HTTP_headers_length = strlen($this->HTTP_headers);
        do {

            if (!$this->STREAM_connect()) {
                continue;
            }

            if (!$this->STREAM_send_headers()) {
                continue;
            }

            if (!$this->STREAM_skip_headers()) {
                continue;
            }

            if (!$this->STREAM_proxy()) {
                continue;
            }
        } while ($this->ERROR_is_accepteble());
    }

    private function HTTP_generate_headers($filename) {
        $header = '';
        self::HTTP_add_header($header, 'GET /' . rawurlencode($filename) . ' HTTP/1.0');
        self::HTTP_add_header($header, 'Host: ' . $this->server_name);
        self::HTTP_add_header($header, 'User-Agent: WinampMPEG/5.11');
        self::HTTP_add_header($header, 'Accept: */*');
        self::HTTP_add_header($header, 'Connection: close');
        //End of headers
        self::HTTP_add_header($header);
        return $header;
    }

    private static function HTTP_add_header(&$header, $new_header_line='') {
        $header.=$new_header_line . self::HTTP_delim;
    }

    private function ERROR_is_accepteble() {
        //Delete old errors
        array_filter($this->STREAM_errors, 'self::ERROR_remove_old');
        $this->STREAM_errors[] = time();
        usleep(self::ERROR_usleep);
        return count($this->STREAM_errors) <= self::ERROR_max;
    }

    private static function ERROR_remove_old($error_time) {
        return ($error_time - time()) <= self::ERROR_interval;
    }

    private function STREAM_connect() {
        if (!ob_get_level()) {
            ob_start();
        }
        ob_clean();
        if ($this->STREAM !== NULL) {
            fclose($this->STREAM);
        }
        $this->STREAM = fsockopen($this->server_name, $this->server_port);

        if ($this->STREAM === FALSE) {
            return FALSE;
        }

        $this->TIMEOUT_seconds = floor(self::STREAM_timeout);
        $this->TIMEOUT_microseconds = ceil((self::STREAM_timeout - $this->TIMEOUT_seconds) * 1000);
        return stream_set_timeout($this->STREAM, $this->TIMEOUT_seconds, $this->TIMEOUT_microseconds);
    }

    private function STREAM_send_headers() {
        return fwrite($this->STREAM, $this->HTTP_headers) === strlen($this->HTTP_headers);
    }

    private function STREAM_skip_headers() {
        $read_expect = array($this->STREAM);

        $if_first_header = true;
        $header_lines_count = 0;

        do {
            stream_select($read_expect, $NULL, $NULL, $this->TIMEOUT_seconds, $this->TIMEOUT_microseconds);

            $header_line = stream_get_line($this->STREAM, self::HTTP_max_line_length, self::HTTP_delim);

            if ($header_line === FALSE) {
                return FALSE;
            }
            if ($if_first_header) {
                $if_first_header = false;

                if (!preg_match(self::HTTP_response_header_first, $header_line)) {
                    return FALSE;
                }
                continue;
            }

            if (empty($header_line)) {
                return TRUE;
            }

            if (!preg_match(self::HTTP_response_header_pattern, $header_line)) {
                return FALSE;
            }

            $header_lines_count++;
        } while ($header_lines_count < self::HTTP_max_response_headers);

        return FALSE;
    }

    private function STREAM_proxy() {
        $read_expect = array($this->STREAM);

        //No output buffering should be here!
        while (@ob_end_clean ());

        do {
            stream_select($read_expect, $NULL, $NULL, $this->TIMEOUT_seconds, $this->TIMEOUT_microseconds);
        } while (fpassthru($this->STREAM));
    }

    private static function STREAM_set_headers() {
        //Clean all output
        ob_clean();
        header("Content-type: " . self::STREAM_content_type);
        ob_flush();
    }

}

$TestRadio = new RadioProxy('XXX.XXX.XXX.XXX', XXXX,'XXXX.mp3');

PS Не делайте этого.

...