FIX: Stream audio in browser (#1872)
This fixes browsers like Safari and allows them to stream audio within the browser vs downloading the audio.
This commit is contained in:
parent
26ac9fb62e
commit
19db155e40
|
|
@ -44,7 +44,7 @@ require_once "resources/check_auth.php";
|
||||||
$order_by = "recording_name";
|
$order_by = "recording_name";
|
||||||
$order = "asc";
|
$order = "asc";
|
||||||
}
|
}
|
||||||
|
|
||||||
//download the recordings
|
//download the recordings
|
||||||
if ($_GET['a'] == "download" && (permission_exists('recording_play') || permission_exists('recording_download'))) {
|
if ($_GET['a'] == "download" && (permission_exists('recording_play') || permission_exists('recording_download'))) {
|
||||||
session_cache_limiter('public');
|
session_cache_limiter('public');
|
||||||
|
|
@ -85,6 +85,11 @@ require_once "resources/check_auth.php";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists($full_recording_path)) {
|
if (file_exists($full_recording_path)) {
|
||||||
|
//content-range
|
||||||
|
if (isset($_SERVER['HTTP_RANGE'])) {
|
||||||
|
range_download($full_recording_path);
|
||||||
|
}
|
||||||
|
|
||||||
$fd = fopen($full_recording_path, "rb");
|
$fd = fopen($full_recording_path, "rb");
|
||||||
if ($_GET['t'] == "bin") {
|
if ($_GET['t'] == "bin") {
|
||||||
header("Content-Type: application/force-download");
|
header("Content-Type: application/force-download");
|
||||||
|
|
@ -104,7 +109,7 @@ require_once "resources/check_auth.php";
|
||||||
header('Content-Disposition: attachment; filename="'.$recording_filename.'"');
|
header('Content-Disposition: attachment; filename="'.$recording_filename.'"');
|
||||||
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
||||||
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
|
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
|
||||||
header("Content-Length: " . filesize($full_recording_path));
|
// header("Content-Length: " . filesize($full_recording_path));
|
||||||
ob_clean();
|
ob_clean();
|
||||||
fpassthru($fd);
|
fpassthru($fd);
|
||||||
}
|
}
|
||||||
|
|
@ -377,4 +382,101 @@ require_once "resources/check_auth.php";
|
||||||
//include the footer
|
//include the footer
|
||||||
require_once "resources/footer.php";
|
require_once "resources/footer.php";
|
||||||
|
|
||||||
|
|
||||||
|
function range_download($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 ($range0 == '-') {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
@ -247,6 +247,16 @@
|
||||||
recording_audio.play();
|
recording_audio.play();
|
||||||
document.getElementById('recording_button_'+recording_id).innerHTML = "<?php echo str_replace("class='list_control_icon'", "class='list_control_icon' style='opacity: 1;'", $v_link_label_pause); ?>";
|
document.getElementById('recording_button_'+recording_id).innerHTML = "<?php echo str_replace("class='list_control_icon'", "class='list_control_icon' style='opacity: 1;'", $v_link_label_pause); ?>";
|
||||||
audio_clock = setInterval(function () { update_progress(recording_id); }, 20);
|
audio_clock = setInterval(function () { update_progress(recording_id); }, 20);
|
||||||
|
|
||||||
|
$("[id*=recording_button]").not("[id*=recording_button_"+recording_id+"]").html("<?php echo $v_link_label_play; ?>");
|
||||||
|
$("[id*=recording_progress_bar]").not("[id*=recording_progress_bar_"+recording_id+"]").css('display', 'none');
|
||||||
|
|
||||||
|
$('audio').each(function(){
|
||||||
|
if ($(this).get(0) != recording_audio) {
|
||||||
|
$(this).get(0).pause(); // Stop playing
|
||||||
|
$(this).get(0).currentTime = 0; // Reset time
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
recording_audio.pause();
|
recording_audio.pause();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue