<?php

// Copyright (C) 2009-2015, Cockos Incorporated
// License: GPL
// do not edit this file -- edit stream-config.php

// to broadcast:
//   use latest reaper_shoutcast, and use http://server/stream.php?stream=streamname for the server
// to stream:
//   in Winamp or VLC or whatnot, use http://server/stream.php?stream=streamname
//    (you can optionally append &file.nsv or &file.mp3 to force the file type for the receiving app)

include("stream-config.php");

function write_session_file($fn, $curfn, $session, $name, $title)
{
  $fp = @fopen($fn,"w");
  if ($fp)
  {
    flock($fp,LOCK_EX);
    fwrite($fp,$curfn . "\n" . $session . "\n" . $name . "\n" . $title . "\n");
    flock($fp,LOCK_UN);
    fclose($fp);
  }
}

function read_session_file($fn)
{
  $ret = array();
  $ret["curfn"] = $ret["session"] = $ret["name"] = $ret["title"] = "";
  $fp = @fopen($fn,"r");
  if ($fp)
  {
    flock($fp,LOCK_SH);
    $ret["curfn"] = rtrim(fgets($fp,1024));
    $ret["session"] = rtrim(fgets($fp,1024));
    $ret["name"] = rtrim(fgets($fp,1024));
    $ret["title"] = rtrim(fgets($fp,1024));
    flock($fp,LOCK_UN);
    fclose($fp);
  }
  return $ret;
}

function update_log($rdfilename, $str)
{
  $fp = @fopen($rdfilename . ".log","a");
  if ($fp) {
    fwrite($fp,$str . " " . time() . "\n");
    fclose($fp);
  }
}


// validate stream
$stream_name = trim($_REQUEST['stream']);
if ($stream_name=="") $stream_name = $config_default_stream;

if ($stream_name == "" || !isset($config_streams[$stream_name]))
{
  header($_SERVER["SERVER_PROTOCOL"] . " 401 Invalid Stream");
  die("invalid stream specified");
}
$this_stream = $config_streams[$stream_name];
$leadpath = isset($this_stream["path"]) && $this_stream["path"] != "" ? $this_stream["path"] : $stream_name;
$timeout = isset($this_stream["session_timeout"]) && $this_stream["session_timeout"] > 5 ? 
               $this_stream["session_timeout"] : $config_session_timeout;
$presend = (isset($this_stream["presend"]) && $this_stream["presend"] > 0 ? $this_stream["presend"] : $config_presend)|0;
if ($presend < 1) $presend = 1;

$keep_files = isset($this_stream["keep_files"]) ? $this_stream["keep_files"] : $config_keep_files;

$sessfn = $leadpath . "/" . $stream_name . "_session.txt";

$now = time();
$is_bc = (trim($_POST['broadcast']) != "");

clearstatcache();

if ($is_bc)
{
  if (trim($_POST['broadcast']) != $this_stream["password"]) 
  {
    header($_SERVER["SERVER_PROTOCOL"] . " 401 Invalid Password");
    die("invalid password");
  }

  if (!$_FILES || !($file = $_FILES["file"])) die("no file sent");
  
  if (!is_dir($leadpath)) @mkdir($leadpath,0775);

  $sessinfo = read_session_file($sessfn);

  $last_file = $sessinfo["curfn"];
  $last_sess = $sessinfo["session"];
  $this_sess = filter_var($_REQUEST['session'],FILTER_SANITIZE_NUMBER_INT);

  if ($last_sess != $this_sess || 
      $last_file == "" ||
      abs(@filemtime($leadpath . "/" . $last_file) - time()) > $timeout)
  {
    if (!$keep_files && $last_file != "") 
    {
      @unlink($leadpath . "/" . $last_file);
      @unlink($leadpath . "/" . $last_file . ".log");
    }

    $sessinfo["curfn"] =  $stream_name . "_" . date("ymd_His") . ".mp3";
  }

  if ($last_file != $sessinfo["curfn"] ||
      rtrim($_REQUEST['name']) != $sessinfo["name"] ||
      rtrim($_REQUEST['title']) != $sessinfo["title"])
  {
    write_session_file($sessfn,$sessinfo["curfn"], $this_sess,$_REQUEST['name'],$_REQUEST['title']);
    update_log($leadpath . "/" . $sessinfo["curfn"],"BEGIN");
  }

  if (is_uploaded_file($file["tmp_name"]))
  {
    $fp = @fopen($file["tmp_name"],"rb");
    $fpo = @fopen($leadpath . "/" . $sessinfo["curfn"],"ab");
    if ($fp && $fpo) while (($x = fread($fp,4096))) fwrite($fpo,$x);
    if ($fp) fclose($fp);
    if ($fpo) fclose($fpo);
    unlink($file["tmp_name"]);
  }

  die;
}

// stream, validate password if set
if ($this_stream["listen_password"] != "" && 
    $this_stream["listen_password"] != trim($_REQUEST["password"])) 
{
  header($_SERVER["SERVER_PROTOCOL"] . " 401 Invalid Stream Password");
  die("invalid password");
}


$sessinfo = read_session_file($sessfn);
$sesslasttime = filemtime($sessfn);
$rdfilename = $leadpath . "/" . $sessinfo["curfn"];

if ($sessinfo["curfn"] == "" || abs(@filemtime($rdfilename) - time()) > $timeout)
{
  header($_SERVER["SERVER_PROTOCOL"] . " 403 Stream Inactive");
  die("stream inactive");
}

if ($_REQUEST['get'] == "info") die($sessinfo["name"] . "\n" . $sessinfo["title"]);
if ($_REQUEST['get'] == "title") die($sessinfo["title"]);

$fp = @fopen($rdfilename,"rb");
if (!$fp)
{
  header($_SERVER["SERVER_PROTOCOL"] . " 403 Stream Inactive");
  die("stream error");
}
@fseek($fp,-$presend,SEEK_END);

set_time_limit(3600*3);
header("Content-type: audio/mpeg");
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
$streamname = trim($sessinfo["name"]);
if ($streamname != "") header("icy-name: $streamname");

$want_title = rtrim($sessinfo["title"]);
if ($want_title == '') $want_title = NULL;

$meta_int=$meta_pos=0;

if ((int)$_SERVER['HTTP_ICY_METADATA'] > 0)
{
  $meta_int = 32000;
  header("icy-metaint: $meta_int");
  if ($_SERVER["SERVER_PROTOCOL"] != "HTTP/1.0")
  {
    // VLC requires an invalid content-length to prevent chunked mode
    if (strstr($_SERVER["HTTP_USER_AGENT"],"VLC")) header("Content-length:-1");
  }
}

$logfile = $rdfilename . ".log";
$log_ident = $_SERVER["REMOTE_ADDR"] . "_" . time();
update_log($rdfilename, "CONNECT $log_ident");
$next_log_update = time() + 30;
while (!connection_aborted())
{
  if (time() > $next_log_update) 
  {
    $next_log_update = time() + 30;
    update_log($rdfilename,"UPDATE $log_ident");
  }
  $rdamt = 4096;
  if ($meta_int > 0 && $rdamt > ($meta_int-$meta_pos)) $rdamt = ($meta_int - $meta_pos);
  $buf = fread($fp,$rdamt);
  if ($buf === FALSE)
  {
    usleep(500*1000);
    clearstatcache();
    if (abs(@filemtime($rdfile) - time()) > $timeout) 
    {
      break;
    }
  }
  else
  {
    echo $buf;
    if ($meta_int > 0)
    {
      $meta_pos += strlen($buf);
      if ($meta_pos >= $meta_int)
      {
        $meta_pos=0;
        clearstatcache();
        $sesstime = filemtime($sessfn);
        if ($sesstime != $sesslasttime)
        {
          $sessinfo = read_session_file($sessfn);
          $sesslasttime = $sesstime;
          $title = rtrim($sessinfo["title"]);
          if ($title !== $want_title) $want_title=$title;
        }

        if ($want_title !== NULL) 
        {
          $want_title = "StreamTitle='" . str_replace("'","",$want_title) . "';";
          $tb=(int) (((strlen($want_title) + 1 + 15)/16));
          echo chr($tb);
          echo $want_title;
          $tb = $tb*16 - strlen($want_title);
          while ($tb-- > 0) echo chr(0);
          $want_title=NULL;
        }
        else echo chr(0);
      }
    }
  }
}
update_log($rdfilename, "DISCONNECT $log_ident");
if ($fp) fclose($fp);
?>
