Ответ 1
Можете ли вы разместить заголовки, отправленные сервером как с PHP, так и без него? script? Мне интересно, если PHP скрипт отправляет другой Content-Type
, чем обычно обслуживает файлы.
Также было бы полезно указать атрибут type
для элементов source
, поэтому браузеру не нужно загружать оба клипа, чтобы определить, может ли он воспроизводиться.
Я не могу воспроизвести вашу проблему. Я попытался воссоздать проблему в Safari 4.0.4 и в текущем WebKit с помощью следующей тестовой страницы. Я просто использую mod_rewrite для отправки в разные форматы на основе параметра вместо PHP, но я не думаю, что это должно иметь значение, если только PHP не модифицирует файл.
<!DOCTYPE html>
<title>Auido test</title>
<audio controls autobuffer>
<source src="gnossienne-no-1?foo=bar&format=.mp4">
<source src="gnossienne-no-1?foo=bar&format=.ogg">
</audio>
Можете ли вы попробовать мой пример и сообщить мне, если он работает для вас?
изменить. Похоже, что это немного связано с тем, что проблема связана с тем, что элемент <audio>
в Safari ведет себя в попытке определить размер содержимого.
Здесь выдержка из пакета захвата Safari при столкновении с элементом <audio>
, указывающим на файл, который подается непосредственно из Apache. Как вы можете видеть, сначала он пытается извлечь первые два байта носителя, предположительно, чтобы получить длину Content-Length и, возможно, другие заголовки. Затем он пытается извлечь все это. Затем, необъяснимо, он пытается снова получить первые два байта, но передает соответствующие заголовки кеширования, чтобы получить ответ "304 Not Modified". И, наконец, все еще необъяснимо, он извлекает последние 3440 байт файла снова и снова. Он делает все это в отдельных TCP-соединениях, что добавляет значительные накладные расходы в дополнение к накладным расходам на выборку данных пару раз.
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=0-1 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] HTTP/1.1 206 Partial Content Date: Tue, 05 Jan 2010 02:12:48 GMT Server: Apache Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT ETag: "b2a80ad-11f6-47c6139aaa800" Accept-Ranges: bytes Content-Length: 2 Content-Range: bytes 0-1/4598 Connection: close Content-Type: audio/mpeg # 2 bytes of data GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=0-4597 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] HTTP/1.1 206 Partial Content Date: Tue, 05 Jan 2010 02:12:48 GMT Server: Apache Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT ETag: "b2a80ad-11f6-47c6139aaa800" Accept-Ranges: bytes Content-Length: 4598 Content-Range: bytes 0-4597/4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=0-1 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] If-None-Match: "b2a80ad-11f6-47c6139aaa800" If-Modified-Since: Tue, 05 Jan 2010 02:02:08 GMT HTTP/1.1 304 Not Modified Date: Tue, 05 Jan 2010 02:12:49 GMT Server: Apache Connection: close ETag: "b2a80ad-11f6-47c6139aaa800" # no data GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=1158-4597 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] HTTP/1.1 206 Partial Content Date: Tue, 05 Jan 2010 02:12:49 GMT Server: Apache Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT ETag: "b2a80ad-11f6-47c6139aaa800" Accept-Ranges: bytes Content-Length: 3440 Content-Range: bytes 1158-4597/4598 Connection: close Content-Type: audio/mpeg # 3440 bytes of data
Во всяком случае, о том, как он относится к выходу вашего PHP script. Здесь Safari снова пытается загрузить первые два байта, но ваш script игнорирует запрос Range
и возвращает все это. По-видимому, WebKit этого не нравится, и поэтому он пытается снова, без запроса Range
. Опять же, ваш script отправляет полное содержимое. Safari теперь пытается повторить попытку, добавив заголовок Icy-Metadata
, который указывает, что он считает, что он загружает поток и хочет передавать потоковые метаданные. Он, наконец, принимает результат этого, и элемент <audio>
может играть.
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 Host: tts.mindtrove.info Range: bytes=0-1 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity HTTP/1.1 200 OK Date: Tue, 05 Jan 2010 02:14:28 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 Host: tts.mindtrove.info Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* HTTP/1.1 200 OK Date: Tue, 05 Jan 2010 02:14:28 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 Host: tts.mindtrove.info Accept: */* User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Icy-Metadata: 1 Connection: close HTTP/1.1 200 OK Date: Tue, 05 Jan 2010 02:14:28 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data
В целом, похоже, что Safari (или, точнее, QuickTime, которое Safari использует для обработки всех носителей и загрузки мультимедиа), имеет абсолютно бесстрашный подход к загрузке медиа. Что-то в том, как вы отправляете свои данные обратно, возможно, тот факт, что вы не отвечаете на запросы Range
, заставляет думать, что вы отправляете потоковые медиа, заставляя его загружать контент повторно (хотя даже при столкновении с сервером который отвечает на запрос Range
, он по-прежнему выполняет еще несколько запросов, чем это действительно необходимо).
Моим советом было бы попытаться ответить соответствующим образом на Range
запросы; при обслуживании носителей, браузеры, скорее всего, будут использовать их, чтобы попытаться минимизировать пропускную способность, за счет буферизации столько, сколько им нужно, чтобы иметь возможность играть (хотя есть атрибут autobuffer
, который указывает, что вы хотели бы, чтобы они забуферили все это, браузеры могут игнорировать это). Я бы рекомендовал использовать X-Sendfile
, чтобы Apache имел дело с обслуживанием файлов, кешированием и запросами диапазона, но вы, кажется, находились на Dreamhost, у которого нет mod_xsendfile
, поэтому вам придется сворачивать ваши собственная обработка Range
.