<?

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

// to broadcast:
//   use latest reaper_shoutcast, and use http://server/path_to_thisfile.php?stream=streamname for the server
// to stream:
//   in Winamp or VLC or whatnot, use http://server/pat_to_thisfile.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, $l1, $l2, $l3)
{
  $fp = @fopen($fn,"w");
  if ($fp)
  {
    flock($fp,LOCK_EX);
    fwrite($fp,$l1 . "\n" . $l2 . "\n" . $l3 . "\n");
    flock($fp,LOCK_UN);
    fclose($fp);
  }
}

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


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

if ($stream_name == "" || !($this_stream = $config_streams[$stream_name]))
{
  header($_SERVER["SERVER_PROTOCOL"] . " 401 Invalid Stream");
  die("invalid stream specified");
}

$sessfn = $config_temp_dir . "/" . $stream_name . ".sess";

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


// generate fn list, find oldest item
$fns = array();
$oldest_index = -1;
$oldest_time = 4200000000;
for ($x = 0; $x < $config_num_files; $x ++)
{
  $fns[$x] = $config_temp_dir . "/" . $stream_name . "." . ($x+1);

  $t = @filemtime($fns[$x]);
  if (($is_bc || ($t && $t > $now-60)) && ($oldest_index<0 || $t < $oldest_time))
  {
    $oldest_index = $x;
    $oldest_time = $t;
  }
}


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($config_temp_dir)) @mkdir($config_temp_dir,0775);

  $sessinfo = read_session_file($sessfn);

  $last_sess = (int)$sessinfo[0];
  $this_sess = (int) $_REQUEST['session'];

  if ($last_sess != $this_sess || 
       rtrim($_REQUEST['name']) != $sessinfo[1] ||
       rtrim($_REQUEST['title']) != $sessinfo[2] )
    write_session_file($sessfn,$this_sess,$_REQUEST['name'],$_REQUEST['title']);

  if ($last_sess != $this_sess)
  {
    for ($x = 0; $x < $config_num_files; $x ++) @unlink($fns[$x]); // clear out history
    $oldest_index=0;
  }
  else if ($oldest_index<0) $oldest_index=0;

  @unlink($fns[$oldest_index]);

//  echo "suc maybe: '" . $file["tmp_name"] . "' to '" . $fns[$oldest_index] . "' '" . $file["size"] . "'\n";
  move_uploaded_file($file["tmp_name"], $fns[$oldest_index]);
  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");
}

// make sure stream is up

// advance past old item since it'll likely get replaced soon
if ($oldest_index>=0)
{
  $oldest_index += 1;
  if ($oldest_index >= $config_num_files) $oldest_index = 0;
}

if ($oldest_index < 0 || !($fp = @fopen($fns[$oldest_index],"rb"))) 
{
  header($_SERVER["SERVER_PROTOCOL"] . " 403 Stream Inactive");
  die("stream inactive");
}
$sessinfo = read_session_file($sessfn);
$sesstime = filemtime($sessfn);

if ($_REQUEST['get'] == "title") die($sessinfo[2]);

set_time_limit(3600*3);
header("Content-type: audio/x-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[1]);
if ($streamname != "") header("icy-name: $streamname");

$want_title = rtrim($sessinfo[2]);

$meta_block = "";
$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");
  }
}

while (!connection_aborted())
{
  if (!$fp) 
  {
    clearstatcache();
    if ( ($t=@filemtime($fns[$oldest_index])) >= $oldest_time && 
         @filesize($fns[$oldest_index])>0 && 
          ($fp = @fopen($fns[$oldest_index],"rb")))
    {
      $oldest_time = $t;
      if ($meta_int > 0 && $want_title == "")
      {
        $t = filemtime($sessfn);
        if ($t > $sesstime)
        {
          $oldtitle = rtrim($sessinfo[2]);
          $sessinfo = read_session_file($sessfn);
          $sesstime=$t;
          if ($oldtitle != rtrim($sessinfo[2])) $want_title = rtrim($sessinfo[2]);
        }
      }
    }
    else 
    {
      if (time() > $last_read_time + $config_file_timeout)
      {
        break;
      }
      usleep(250000);
    }
  }
  else
  {
    $rdamt = 4096;
    if ($meta_int > 0 && $rdamt > ($meta_int-$meta_pos)) $rdamt = ($meta_int - $meta_pos);
    $buf = fread($fp,$rdamt);
    if ($buf == '')
    {
      fclose($fp);
      $fp = 0;

      $oldest_index += 1;
      if ($oldest_index >= $config_num_files) $oldest_index = 0;
    }
    else 
    {
      echo $buf;
      $last_read_time = time();

      if ($meta_int > 0)
      {
        $meta_pos += strlen($buf);
        if ($meta_pos >= $meta_int)
        {
          $meta_pos=0;
          if ($want_title != "") 
          {
            $want_title = str_replace("'","",$want_title);
            $want_title = "StreamTitle='$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="";
          }
          else echo chr(0);
          $meta_block = "";
        }
      }
    }
  }
}

if ($fp) fclose($fp);


?>
