summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/ampache.cfg.php.dist31
-rwxr-xr-xdocs/CHANGELOG3
-rw-r--r--lib/general.lib.php79
-rw-r--r--lib/rss.php3
-rw-r--r--lib/stream.lib.php249
-rw-r--r--modules/init.php3
-rw-r--r--play/index.php48
-rw-r--r--server.php12
8 files changed, 298 insertions, 130 deletions
diff --git a/config/ampache.cfg.php.dist b/config/ampache.cfg.php.dist
index bf727079..38940ad4 100644
--- a/config/ampache.cfg.php.dist
+++ b/config/ampache.cfg.php.dist
@@ -18,13 +18,6 @@
# DEFAULT: ""
#web_path = ""
-
-# Lang (define the locale you want to use
-# this is a cheeseball fix for now it will be smarter
-# later.
-# DEFAULT: en_US
-#lang = "en_US"
-
####################
# The libglue Vars #
####################
@@ -266,6 +259,28 @@ allow_stream_playback = true
#allow_slim_playback = false
#######################################################
+# These options control the dynamic downsampling based
+* on current useage
+# *Note* Downsampling must be enabled and working
+#######################################################
+
+# Attempt to optimize bandwidth by dynamically downsampling
+# all connections from users to fit within a maximum bandwidth.
+# The benefit is that it won't downsample more than it needs to. As it only
+# adjusts the sample rate at the beginning of a song, it may take a few
+# minutes to reset all connections to a lower rate. This won't never go higher
+# than a user's sample rate and only applies to users who are set to
+# the Downsample playback method
+# DEFAULT: 576
+#max_bit_rate = 576
+
+# If min_bit_rate is set then new streams will be denied if it would
+# cause all streams to be downsampled below this rate.
+# DEFAULT: 48
+#min_bit_rate = 48
+
+
+#######################################################
# These options control how searching works
#######################################################
@@ -460,7 +475,7 @@ rss_song_description = <![CDATA[$song->f_title @ $album played by $user->fullna
# If set to true MPD is not displayed on the main page, but on it's
# own distinct page. This is called localplay, because eventually
-# it will control all "LOCAL" style play methods including localplay
+# it will control all "LOCAL" style play methods including localplay, xmms2
# and the slimserver
# DEFAULT: false
#localplay_menu = true
diff --git a/docs/CHANGELOG b/docs/CHANGELOG
index be4b9bf2..1cae7418 100755
--- a/docs/CHANGELOG
+++ b/docs/CHANGELOG
@@ -17,6 +17,9 @@
it handles it correctly, and doesn't remove the row after
the script execution has finished, and depends upon the
GC to catch it
+ - Added Optional Automatic Bandwidth management for downsampled
+ users based on defined bandwidth limits (Thx Jens)
+ - Prevented Load of XML-RPC library if xml_rpc isn't enabled
--------------------------------------------------------------------------
diff --git a/lib/general.lib.php b/lib/general.lib.php
index 297ac667..16d0ac11 100644
--- a/lib/general.lib.php
+++ b/lib/general.lib.php
@@ -743,83 +743,4 @@ function tbl_name($table) {
} // tbl_name
-/**
- * insert_now_playing
- * This function takes care of inserting the now playing data
- * we use this function because we need to do thing differently
- * depending upon which play is actually streaming
- * @package General
- * @catagory Now Playing
- */
-function insert_now_playing($song_id,$uid,$song_length) {
-
- $user_agent = $_SERVER['HTTP_USER_AGENT'];
- $time = time();
-
- /* Windows Media Player is evil and it makes multiple requests per song */
- if (stristr($user_agent,"NSPlayer")) { return false; }
-
- /* Set the Expire Time */
-
- // If they are using Windows media player
- if (stristr($user_agent,"Windows-Media-Player")) {
- // WMP does keep the session open so we need to cheat a little here
- $expire = $time + $song_length;
- }
- else {
- $expire = $time;
- }
-
- $sql = "INSERT INTO now_playing (`song_id`, `user`, `start_time`)" .
- " VALUES ('$song_id', '$uid', '$expire')";
-
- $db_result = mysql_query($sql, dbh());
-
- $insert_id = mysql_insert_id(dbh());
-
- return $insert_id;
-
-} // insert_now_playing
-
-/**
- * delete_now_playing
- * This function checks to see if we should delete the last now playing entry now that it's
- * finished streaming the song. Basicly this is an exception for WMP10
- * @package General
- * @catagory Now Playing
- */
-function delete_now_playing($insert_id) {
-
- $user_agent = $_SERVER['HTTP_USER_AGENT'];
-
- if (stristr($user_agent,"Windows-Media-Player")) {
- // Commented out until I can figure out the
- // trick to making this work
- //return true;
- }
-
-
- // Remove the song from the now_playing table
- $sql = "DELETE FROM now_playing WHERE id = '$insert_id'";
- $db_result = mysql_query($sql, dbh());
-
-} // delete_now_playing
-
-/**
- * gc_now_playing
- * this is a garbage collection function for now playing this is called every time something
- * is streamed
- * @package General
- * @catagory Now Playing
- */
-function gc_now_playing() {
-
- $time = time();
- $expire = $time - 1800; // 86400 seconds = 1 day
-
- $sql = "DELETE FROM now_playing WHERE start_time < $expire";
- $db_result = mysql_query($sql, dbh());
-
-} // gc_now_playing
-
?>
diff --git a/lib/rss.php b/lib/rss.php
index efb6cba9..4fc849d2 100644
--- a/lib/rss.php
+++ b/lib/rss.php
@@ -1,6 +1,9 @@
<?php
/*
+ Copyright 2001 - 2005 Ampache.org
+ All Rights Reserved
+
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
diff --git a/lib/stream.lib.php b/lib/stream.lib.php
new file mode 100644
index 00000000..a022b6da
--- /dev/null
+++ b/lib/stream.lib.php
@@ -0,0 +1,249 @@
+<?php
+/*
+
+ Copyright 2001 - 2005 Ampache.org
+ All Rights Reserved
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+/**
+ * delete_now_playing
+ * This function checks to see if we should delete the last now playing entry now that it's
+ * finished streaming the song. Basicly this is an exception for WMP10
+ * @package General
+ * @catagory Now Playing
+ */
+function delete_now_playing($insert_id) {
+
+ $user_agent = $_SERVER['HTTP_USER_AGENT'];
+
+ if (stristr($user_agent,"Windows-Media-Player")) {
+ // Commented out until I can figure out the
+ // trick to making this work
+ //return true;
+ }
+
+
+ // Remove the song from the now_playing table
+ $sql = "DELETE FROM now_playing WHERE id = '$insert_id'";
+ $db_result = mysql_query($sql, dbh());
+
+} // delete_now_playing
+
+/**
+ * gc_now_playing
+ * this is a garbage collection function for now playing this is called every time something
+ * is streamed
+ * @package General
+ * @catagory Now Playing
+ */
+function gc_now_playing() {
+
+ $time = time();
+ $expire = $time - 1800; // 86400 seconds = 1 day
+
+ $sql = "DELETE FROM now_playing WHERE start_time < $expire";
+ $db_result = mysql_query($sql, dbh());
+
+} // gc_now_playing
+
+/**
+ * insert_now_playing
+ * This function takes care of inserting the now playing data
+ * we use this function because we need to do thing differently
+ * depending upon which play is actually streaming
+ * @package General
+ * @catagory Now Playing
+ */
+function insert_now_playing($song_id,$uid,$song_length) {
+
+ $user_agent = $_SERVER['HTTP_USER_AGENT'];
+ $time = time();
+
+ /* Windows Media Player is evil and it makes multiple requests per song */
+ if (stristr($user_agent,"NSPlayer")) { return false; }
+
+ /* Set the Expire Time */
+
+ // If they are using Windows media player
+ if (stristr($user_agent,"Windows-Media-Player")) {
+ // WMP does keep the session open so we need to cheat a little here
+ $expire = $time + $song_length;
+ }
+ else {
+ $expire = $time;
+ }
+
+ $sql = "INSERT INTO now_playing (`song_id`, `user`, `start_time`)" .
+ " VALUES ('$song_id', '$uid', '$expire')";
+
+ $db_result = mysql_query($sql, dbh());
+
+ $insert_id = mysql_insert_id(dbh());
+
+ return $insert_id;
+
+} // insert_now_playing
+
+/**
+ * check_lock_songs
+ * This checks to see if the song is already playing, if it is then it prevents the user
+ * from streaming it
+ * @package General
+ * @catagory Security
+ */
+function check_lock_songs($song_id) {
+
+ $sql = "SELECT COUNT(*) FROM now_playing " .
+ "WHERE song_id = '$song_id'";
+ $db_results = mysql_query($sql, dbh());
+
+ if (mysql_num_rows($db_results)) {
+ return false;
+ }
+
+ return true;
+
+} // check_lock_songs
+
+/**
+ * start_downsample
+ * This is a rather complext function that starts the downsampling of a song and returns the
+ * opened file handled
+ * @package General
+ * @catagory Downsample
+ * @param $song The Song Object
+ */
+function start_downsample($song,$now_playing_id=0,$song_name=0) {
+
+ /* Check to see if bitrates are set if so let's go ahead and optomize! */
+ $max_bitrate = conf('max_bitrate');
+ $min_bitrate = conf('min_bitrate');
+ $time = time();
+ $dbh = dbh();
+ $user_sample_rate = $GLOBALS['user']->prefs['sample_rate'];
+ $browser = new Browser();
+
+ if (!$song_name) {
+ $song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type;
+ }
+
+ if ($max_bitrate > 1 AND $min_bitrate < $max_bitrate) {
+ $last_seen_time = $time - 1200; //20 min.
+
+ /**********************************
+ * Commenting out the following, I'd rather have it slightly less accurate and avoid a 4 table join
+ // Count the users connected in the last 20 min using downsampling
+ $sql = "SELECT COUNT(DISTINCT session.username) FROM session,user,user_preference,preferences " .
+ "WHERE user.username = session.username AND session.expire > '$time' AND user.last_seen > $last_seen_time " .
+ "AND preferences.name = 'play_type' AND user_preference.preference = preferences.id AND " .
+ "user_preference.user = user.username AND user_preference.value='downsample'";
+ $db_result = mysql_query($sql, $dbh);
+ $results = mysql_fetch_row($db_result);
+
+ // The current number of connected users
+ $current_users_count = $results[0];
+ ************************************/
+
+
+ $sql = "SELECT COUNT(*) FROM now_playing, user_preference, preferences" .
+ "WHERE preferences.name = 'play_type' AND user_preference.preference = preferences.id " .
+ "AND now_playing.user = user_preference.user AND user_preference.value='downsample'";
+ $db_results = mysql_query($sql,$dbh);
+ $results = mysql_fetch_row($db_result);
+
+ // Current number of active streams + 1 (the one we are starting)
+ $active_streams = $results[0] + 1;
+
+
+ /* If only one user, they'll get all available. Otherwise split up equally. */
+ $sample_rate = floor($max_bitrate/$active_streams);
+
+ /* If min_bitrate is set, then we'll exit if the bandwidth would need to be split up smaller than the min. */
+ if ($min_bitrate > 1 AND ($max_bitrate/$active_streams) < $min_bitrate) {
+
+ /* Log the failure */
+ if (conf('debug')) {
+ log_event($user->username,' downsample ',"Error: Max bandwidith already allocated. $active_streams Active Streams");
+ }
+
+ /* Toast the now playing entry, then tell em to try again later */
+ delete_now_playing($now_playing_id);
+ echo "Maximum bandwidth already allocated. Try again later.";
+ exit();
+
+ }
+ else {
+ $sample_rate = floor($max_bitrate/$active_streams);
+ } // end else
+
+ /* Round to standard bitrates */
+ $sample_rate = 8*(floor($sample_rate/8));
+
+ // Never go over the users sample rate
+ if ($sample_rate > $user_sample_rate) { $sample_rate = $user_sample_rate; }
+
+ if (conf('debug')) {
+ log_event($GLOBALS['user']->username, ' downsample ',"Downsampled: $active_streams current active streams, downsampling to $sample_rate");
+ }
+
+ } // end if we've got bitrates
+
+ else {
+ $sample_rate = $user_sample_rate;
+ }
+
+ /* Never Upsample a song */
+ if (($sample_rate*1000) > $song->bitrate) {
+ unset($sample_rate);
+ }
+
+ $sample_ratio = $sample_rate/($song->bitrate/1000);
+
+ $browser->downloadHeaders($song_name, $song->mime, false,$sample_ratio*$song->size);
+
+ /* Get Offset */
+ $offset = ( $start*$song->time )/( $sample_ratio*$song->size );
+ $offsetmm = floor($offset/60);
+ $offsetss = floor($offset-$offsetmm*60);
+ $offset = sprintf("%02d.%02d",$offsetmm,$offsetss);
+
+ /* Get EOF */
+ $eofmm = floor($song->time/60);
+ $eofss = floor($song->time-$eofmm*60);
+ $eof = sprintf("%02d.%02d",$eofmm,$eofss);
+
+ /* Replace Variables */
+ $downsample_command = conf('downsample_cmd');
+ $downsample_command = str_replace("%FILE%",$song->file,$downsample_command);
+ $downsample_command = str_replace("%OFFSET%",$offset,$downsample_command);
+ $downsample_command = str_replace("%EOF%",$eof,$downsample_command);
+ $downsample_command = str_replace("%SAMPLE%",$sample_rate,$downsample_command);
+
+ // If we are debugging log this event
+ if (conf('debug')) {
+ $message = "Start Downsample: $downsample_command";
+ log_event($GLOBALS['user']->username,' downsample ',$message);
+ } // if debug
+
+ $fp = @popen($downsample_command, 'r');
+
+ return ($fp);
+
+} // start_downsample
+
+?>
diff --git a/modules/init.php b/modules/init.php
index 5974b0e9..d38a5289 100644
--- a/modules/init.php
+++ b/modules/init.php
@@ -83,7 +83,7 @@ if (!$results['conf']['allow_stream_playback']) {
}
$results['conf']['web_path'] = $http_type . $_SERVER['HTTP_HOST'] . $results['conf']['web_path'];
-$results['conf']['version'] = '3.3.2-Alpha2 Build (001)';
+$results['conf']['version'] = '3.3.2-Alpha2 Build (002)';
$results['conf']['catalog_file_pattern']= 'mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx';
$results['libglue']['local_table'] = 'session';
$results['libglue']['local_sid'] = 'id';
@@ -163,6 +163,7 @@ require_once(conf('prefix') . "/lib/ui.lib.php");
require_once(conf('prefix') . "/lib/gettext.php");
require_once(conf('prefix') . "/lib/batch.lib.php");
require_once(conf('prefix') . "/lib/themes.php");
+require_once(conf('prefix') . "/lib/stream.lib.php");
require_once(conf('prefix') . "/modules/lib.php");
require_once(conf('prefix') . "/modules/admin.php");
require_once(conf('prefix') . "/modules/catalog.php");
diff --git a/play/index.php b/play/index.php
index 874de187..660ae9d4 100644
--- a/play/index.php
+++ b/play/index.php
@@ -138,6 +138,8 @@ if ( $catalog->catalog_type == 'remote' ) {
header("Location: " . $song->file . $extra_info);
if (conf('debug')) { log_event($user->username,' xmlrpc-stream ',"Start XML-RPC Stream - " . $song->file . $extra_info); }
}
+
+
else {
if ($user->prefs['play_type'] == 'downsample') {
$ds = $user->prefs['sample_rate'];
@@ -150,16 +152,8 @@ else {
gc_now_playing();
// If we are running in Legalize mode, don't play songs already playing
- if (conf('lock_songs') == 'true') {
- $sql = "SELECT COUNT(*) FROM now_playing" .
- " WHERE song_id = '$song_id'";
- $db_result = mysql_query($sql, $dbh);
- while ($r = mysql_fetch_row($db_result)) {
- if ($r[0] == 1) {
- // Song is already playing, so exit without returning song
- exit;
- }
- }
+ if (conf('lock_songs')) {
+ if (!check_lock_songs($song->id)) { exit(); }
}
// Put this song in the now_playing table
@@ -214,37 +208,11 @@ else {
// Prevent the script from timing out
set_time_limit(0);
- if ($ds) {
- $ds = $user->prefs['sample_rate'];
- $dsratio = $ds/$song->bitrate*1024;
- $browser->downloadHeaders($song_name, $song->mime, false,$dsratio*$song->size);
-
- /* Get Offset */
- $offset = ( $start*$song->time )/( $dsratio*$song->size );
- $offsetmm = floor($offset/60);
- $offsetss = floor($offset-$offsetmm*60);
- $offset = sprintf("%02d.%02d",$offsetmm,$offsetss);
+ if ($user->prefs['play_type'] == 'downsample') {
- /* Get EOF */
- $eofmm = floor($song->time/60);
- $eofss = floor($song->time-$eofmm*60);
- $eof = sprintf("%02d.%02d",$eofmm,$eofss);
-
- /* Replace Variables */
- $downsample_command = conf('downsample_cmd');
- $downsample_command = str_replace("%FILE%",$song->file,$downsample_command);
- $downsample_command = str_replace("%OFFSET%",$offset,$downsample_command);
- $downsample_command = str_replace("%EOF%",$eof,$downsample_command);
- $downsample_command = str_replace("%SAMPLE%",$ds,$downsample_command);
-
- // If we are debugging log this event
- if (conf('debug')) {
- $message = "Exec: $downsample_command";
- log_event($user->username,'downsample',$message);
- } // if debug
+ $fp = start_downsample($song,$lastid,$song_name);
- $fp = @popen($downsample_command, 'r');
- } // if downsampling
+ } // end if downsampling
elseif ($start) {
$browser->downloadHeaders($song_name, $song->mime, false, $song->size);
@@ -282,7 +250,7 @@ else {
delete_now_playing($lastid);
/* Clean up any open ends */
- if ($ds) {
+ if ($user->prefs['play_type'] == 'downsample') {
@pclose($fp);
}
else {
diff --git a/server.php b/server.php
index 5f293206..3ef233bd 100644
--- a/server.php
+++ b/server.php
@@ -1,6 +1,9 @@
<?php
/*
+ Copyright 2001 - 2005 Ampache.org
+ All Rights Reserved
+
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
@@ -19,8 +22,13 @@
$no_session = true;
require_once('modules/init.php');
-require_once(conf('prefix') . "/modules/xmlrpc/xmlrpcs.inc");
-require_once(conf('prefix') . "/modules/xmlrpc/xmlrpc.inc");
+
+
+if (conf('xml_rpc')) {
+ require_once(conf('prefix') . "/modules/xmlrpc/xmlrpcs.inc");
+ require_once(conf('prefix') . "/modules/xmlrpc/xmlrpc.inc");
+}
+else { exit(); }
/* Setup the vars we are going to need */
$access = new Access();