3

I have an <audio> element with controls like so:

<audio controls="controls" id="audio-sample" preload="auto">
    <source src="../../music-sample.php?type=ogg&amp;id=<?php echo $item->custom_5; ?>" type="audio/ogg" />
    <source src="../../music-sample.php?type=mp3&amp;id=<?php echo $item->custom_5; ?>" type="audio/mp3" />
</audio>

The player shows up, and the sound plays just fine, but the trackbar doesn't move to reflect the elapsed time, and it can't be dragged to seek. Why not? Do I need to send some sort of additional header? This is all the relevant PHP, nothing special:

header('Content-Type: ' . $mimetype[$type]);

$file = fopen($filename, 'rb');
fpassthru($file);
fclose($file);
exit();

You can see the problem live here.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 2
    What's the advantage of explicitly sending the file's contents over just `readfile()`? – alex Nov 01 '12 at 04:08
  • @alex: None, I didn't know `readfile` existed. Thanks! (And I'll try the `Content-Length` thing now. I don't think it worked once upon a time, but who knows!) – Ry- Nov 01 '12 at 04:24
  • @alex: `Content-Length` worked perfectly. Arrgh, sorry! Please post that as an answer :) – Ry- Nov 01 '12 at 04:25

4 Answers4

4

Try setting the Content-Length header...

header("Content-Length: " . filesize($filename));

For some reason without that info up front, it can't do the necessary math to place the track bar.

alex
  • 479,566
  • 201
  • 878
  • 984
  • Actually, although you can still seek on Firefox (in the area that's already played), the track thumb starts and stays at the end of the bar. Any ideas? – Ry- Nov 02 '12 at 01:05
  • @minitech I'm not sure sorry, I haven't used the `audio` element too much. I'll have a look though. – alex Nov 02 '12 at 01:33
  • As Apache is replacing the Content-Length header with Transfer-Encoding: chunked; I am unable to get the seek bar working. Any approach to solve this problem? – Ahamed Jun 19 '14 at 13:33
2

The trick to getting it working on Firefox and Safari specifically is to send a Content-Range header, as described here.

$length = filesize($filename);

header('Content-Type: ' . $mimetype[$type]);
header('Content-Length: ' . $length);
header('Content-Range: bytes 0-' . ($length - 1) . '/' . $length);

readfile($filename);
Community
  • 1
  • 1
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • I just ran in to this, and it looks like `header('Accept-Ranges: bytes');` resolved the problem for me! I got clued on to this from your question related to this issue. Clearly, there are some implementation issues in all the user agents :( – Chris Baker Aug 13 '13 at 17:34
1

My Experience

There is nothing wrong with your code. I had this issue once and .. And it was a simple cache issue on Firefox and Content-Length which you have discovered

c.php

<audio controls="controls" id="audio-sample" preload="auto">
    <source src="a.php?type=ogg&id=0" type="audio/ogg" />
    <source src="a.php?type=mp3&id=1" type="audio/mp3" />
</audio>

a.php

$id = intval($_GET['id']);
$files = array(0 => "audio.ogg",1 => "audio.mp3");
$filename = $files[$id];

header('Content-Type: ' . mime_content_type($filename));
header("Content-transfer-encoding: binary");
header("Content-Length: " . filesize($filename));

ob_clean();
flush();
readfile($filename);
exit();

This worked 100% in Firefox but when i changed readfile($filename) to

  readfile("SIMPLE ERROR ERROR");

Firefox sill pays the audio for me instead of not paying any file the only way to make it realize the mistake was to add a random string to the src file

<source src="a.php?type=ogg&id=0&<?php echo mt_rand(); ?>" type="audio/ogg" />
                                             ^---- rand string

This way the URL was requested Firefox stooped playing the audio instantly

The Problem

Because you have tried to stream the content before with Zero Content-Length that is sill the reason your audio is not paying ..... Firefox has cached the initial invalid content

Solution

Clear all your cache .. with the following code above your code should work fine or just add the rand parameter in your code for testing

enter image description here

Invalid Relative Position

Permanently using mt_rand() would make it difficult for Firefox to cache the audio file which results in Invalid Relative solution.

Remove the mt_rand after the cleaning of cache and this would be fixed

Baba
  • 94,024
  • 28
  • 166
  • 217
  • 1
    Thanks, that was indeed part of it! But now it shows the current position relative to what's buffered so far, and it doesn't seem to want to buffer all of it in advance, just about one second. Any ideas? – Ry- Nov 09 '12 at 15:50
  • Firefox only has valid relative position for cache audio files ... If you play the audio the second time you would notice that the relative position becomes fixed ... Solution .. remove the mt_rand and you are fine .... – Baba Nov 09 '12 at 17:26
  • I didn't add a random number for testing - it still only shows the position relative to the first five seconds or so. – Ry- Nov 09 '12 at 17:40
  • @minitech ... after playing the audio for the second time does it do the same ? – Baba Nov 10 '12 at 01:58
  • Use `` without PHP and check if it does the same .. What version of firefox are you using – Baba Nov 10 '12 at 02:09
1

A combination of Content-Type = audio/ogg, Content-Length, Accept-Ranges = bytes, and most importantly, I think the X-Content-Duration response headers is what has worked for me.

The X-Content-Duration header tells clients what the duration of an ogg file is, in seconds. Here's some more info about it https://developer.mozilla.org/en-US/docs/Configuring_servers_for_Ogg_media.

Each frame of an ogg file might be encoded with a variable number of bits, so just knowing the file size in bytes doesn't tell you the file length in seconds. You can tell clients this explicitly for ogg vorbis files with the X-Content-Duration header.

John Vinyard
  • 12,997
  • 3
  • 30
  • 43