blob: 2b92c51d879fd1e9dd42d9810e96365511415b7e [file] [log] [blame]
<?php
// This script is based on the work done by gadgetguru
// <david@vuistbijl.nl> at
// https://github.com/gadgetguru/PHP-Streaming-Audio and released
// under the Public Domain.
// Set variables
$settings = array(
"chunkSize" => array_key_exists("chunkSize", $_GET) ? $_GET["chunkSize"] : 1024 * 256,
"databaseFile" => "metadata.db",
"httpStatus" => "500 Internal Server Error",
"mediaDirectory" => array_key_exists("name", $_GET) ? dirname($_GET["name"]) : "",
"mimeType" => array_key_exists("type", $_GET) ? $_GET["type"] : "",
"radioGenre" => "Rock",
"radioName" => "WebKit Test Radio",
"radioUrl" => (array_key_exists("HTTPS", $_SERVER) ? "https" : "http") . "://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"],
"setContentLength" => array_key_exists("content-length", $_GET) ? $_GET["content-length"] : "yes",
"setIcyData" => array_key_exists("icy-data", $_GET) ? $_GET["icy-data"] : "no",
"supportRanges" => array_key_exists("ranges", $_GET) ? $_GET["ranges"] : "yes",
"stallOffset" => array_key_exists("stallOffset", $_GET) ? $_GET["stallOffset"] : 0,
"stallDuration" => array_key_exists("stallDuration", $_GET) ? $_GET["stallDuration"] : 2,
);
// 500 on errors
if (!array_key_exists("name", $_GET)) {
trigger_error("You have not specified a 'name' parameter.", E_USER_WARNING);
goto answering;
}
$fileName = $_GET["name"];
if (!file_exists($fileName)) {
trigger_error("The file '" . $fileName . "' doesn't exist.", E_USER_WARNING);
goto answering;
}
$settings["databaseFile"] = $settings["mediaDirectory"] . "/" . $settings["databaseFile"];
if ($settings["setIcyData"] != "yes" && $settings["mimeType"] == "") {
trigger_error("You have not specified a 'type' parameter.", E_USER_WARNING);
goto answering;
}
if ($settings["setIcyData"] == "yes") {
if (!file_exists($settings["databaseFile"])) {
// If the metadata database file doesn't exist it has to
// be create previously.
//
// Check the instructions about how to create it from the
// create-id3-db.php script file in this same directory.
trigger_error("The metadata database doesn't exist. To create one, check the script 'create-id3-db.php'.", E_USER_WARNING);
goto answering;
}
$playFiles = unserialize(file_get_contents($settings["databaseFile"]));
foreach ($playFiles as $i=>$playFile) {
if (basename($fileName) == $playFile["fileName"]) {
$fileInDB = true;
break;
}
}
if (!isset($fileInDB)) {
trigger_error("The requested file is not in the database.", E_USER_WARNING);
goto answering;
}
}
// There is everything needed to send the media file
$fileSize = filesize($fileName);
if ($settings["stallOffset"] && ($settings["stallOffset"] > $fileSize)) {
trigger_error("The 'stallOffset' offset parameter is greater than file size (" . $fileSize . ").", E_USER_WARNING);
goto answering;
}
$start = 0;
$end = $fileSize - 1;
if ($settings["supportRanges"] != "no" && array_key_exists("HTTP_RANGE", $_SERVER))
$contentRange = $_SERVER["HTTP_RANGE"];
if (isset($contentRange)) {
$range = explode("-", substr($contentRange, strlen("bytes=")));
$start = intval($range[0]);
if (!empty($range[1]))
$end = intval($range[1]);
$settings["httpStatus"] = "206 Partial Content";
} else
$settings["httpStatus"] = "200 OK";
answering:
header("Status: " . $settings["httpStatus"]);
header("HTTP/1.1 " . $settings["httpStatus"]);
header("Connection: close");
if ($settings["httpStatus"] == "500 Internal Server Error") {
header("Content-Type: text/html");
$errorMessage = sprintf("<html><body><h1>%s</h1><p/>",
$settings["httpStatus"]);
if (function_exists("error_get_last")) {
$errorArray = error_get_last();
if ($errorArray) {
$errorMessage = sprintf("%sError type: %d<p/>Error message: %s<p/>".
"Error file: %s<p/>Error line: %d<p/>",
$errorMessage, $errorArray["type"], $errorArray["message"],
$errorArray["file"], $errorArray["line"]);
}
}
$errorMessage = $errorMessage . "</body><html>";
print($errorMessage);
flush();
exit;
}
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache");
header("Etag: " . '"' . $fileSize . "-" . filemtime($fileName) . '"');
if ($settings["setIcyData"] == "yes") {
$bitRate = ceil($playFiles[$i]["bitRate"] / 1000);
if ($settings["mimeType"] == "")
$settings["mimeType"] = $playFiles[$i]["mimeType"];
header("icy-notice1: <BR>This stream requires a shoutcast/icecast compatible player.<BR>");
header("icy-notice2: WebKit Stream Test<BR>");
header("icy-name: " . $settings["radioName"]);
header("icy-genre: " . $settings["radioGenre"]);
header("icy-url: " . $settings["radioUrl"]);
header("icy-pub: 1");
header("icy-br: " . $bitRate);
}
header("Content-Type: " . $settings["mimeType"]);
if ($settings["supportRanges"] != "no")
header("Accept-Ranges: bytes");
if ($settings["setContentLength"] != "no")
header("Content-Length: " . ($end - $start + 1));
if (isset($contentRange))
header("Content-Range: bytes " . $start . "-" . $end . "/" . $fileSize);
$offset = $start;
$fn = fopen($fileName, "rb");
fseek($fn, $offset, 0);
if ($settings["stallDuration"])
set_time_limit(0);
$stalledOnce = false;
while (!feof($fn) && $offset <= $end && connection_status() == 0) {
$readSize = min($settings["chunkSize"], ($end - $offset) + 1);
$stallNow = false;
if (!$stalledOnce && $settings["stallOffset"] && $settings["stallOffset"] >= $offset && $settings["stallOffset"] < $offset + $readSize) {
$readSize = min($settings["chunkSize"], $settings["stallOffset"] - $offset);
$stallNow = true;
}
$buffer = fread($fn, $readSize);
$readLength = strlen($buffer);
print($buffer);
flush();
$offset += $readLength;
if ($stallNow) {
sleep($settings["stallDuration"]);
$stalledOnce = true;
}
}
fclose($fn);
exit;
?>