[xiph-commits] r15372 - in icecast/branches/kh/icecast: . admin src web win32
karl at svn.xiph.org
karl at svn.xiph.org
Fri Oct 3 18:09:17 PDT 2008
Author: karl
Date: 2008-10-03 18:09:17 -0700 (Fri, 03 Oct 2008)
New Revision: 15372
Removed:
icecast/branches/kh/icecast/debian/
Modified:
icecast/branches/kh/icecast/Makefile.am
icecast/branches/kh/icecast/NEWS
icecast/branches/kh/icecast/admin/showlog.xsl
icecast/branches/kh/icecast/config.h.vc6
icecast/branches/kh/icecast/configure.in
icecast/branches/kh/icecast/src/admin.c
icecast/branches/kh/icecast/src/auth_htpasswd.c
icecast/branches/kh/icecast/src/cfgfile.h
icecast/branches/kh/icecast/src/connection.c
icecast/branches/kh/icecast/src/format.c
icecast/branches/kh/icecast/src/format.h
icecast/branches/kh/icecast/src/format_kate.c
icecast/branches/kh/icecast/src/format_mp3.c
icecast/branches/kh/icecast/src/format_ogg.c
icecast/branches/kh/icecast/src/format_ogg.h
icecast/branches/kh/icecast/src/format_theora.c
icecast/branches/kh/icecast/src/fserve.c
icecast/branches/kh/icecast/src/global.c
icecast/branches/kh/icecast/src/refbuf.c
icecast/branches/kh/icecast/src/refbuf.h
icecast/branches/kh/icecast/src/slave.c
icecast/branches/kh/icecast/src/source.c
icecast/branches/kh/icecast/src/stats.c
icecast/branches/kh/icecast/src/stats.h
icecast/branches/kh/icecast/src/util.c
icecast/branches/kh/icecast/src/util.h
icecast/branches/kh/icecast/src/yp.c
icecast/branches/kh/icecast/web/status.xsl
icecast/branches/kh/icecast/win32/icecast.dsp
icecast/branches/kh/icecast/win32/icecast2.iss
Log:
bump version, drop debian directory as it's unmaintained here. some more thread
removal work for stats, video preview merge (not built by default) and a couple
of bug fixes from reported feedback.
Modified: icecast/branches/kh/icecast/Makefile.am
===================================================================
--- icecast/branches/kh/icecast/Makefile.am 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/Makefile.am 2008-10-04 01:09:17 UTC (rev 15372)
@@ -3,7 +3,7 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = src conf debian doc web admin win32
+SUBDIRS = src conf doc web admin win32
EXTRA_DIST = HACKING config.h.vc6 m4/acx_pthread.m4 m4/ogg.m4 \
m4/theora.m4 m4/vorbis.m4 m4/speex.m4\
Modified: icecast/branches/kh/icecast/NEWS
===================================================================
--- icecast/branches/kh/icecast/NEWS 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/NEWS 2008-10-04 01:09:17 UTC (rev 15372)
@@ -15,6 +15,21 @@
any extra tags are show in the conf/icecast.xml.dist file
+2.3.2-kh2
+. more stats work. Clients are now processed as needed instead of a dedicated
+ thread per stats client.
+. don't allow raw metadata updates if not from the same IP address as the source
+ client unless it is from the admin user. For some reason some source client
+ issue updates even though they are rejected.
+. missing lock on streamlist master/slave update, could cause memory corruption.
+. update to average bitrate handling.
+. allow strftime expansion on dump filename, applies at the time the stream has
+ started
+. removed debian directory, it's not maintained really so leave it to the debian
+ people to deal with it themselves.
+. experimental theora keyframe as png patch added. not built by default
+. minor memory leak plugged in fserve
+
2.3.2-kh1
. remove stats thread. Stats clients still have their own thread and queue.
. fix low bandwidth theora stream problem.
Modified: icecast/branches/kh/icecast/admin/showlog.xsl
===================================================================
--- icecast/branches/kh/icecast/admin/showlog.xsl 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/admin/showlog.xsl 2008-10-04 01:09:17 UTC (rev 15372)
@@ -7,7 +7,7 @@
<head>
<title>Icecast log files</title>
</head>
-<body style="color: white; font-size: 90%">
+<body bgcolor="#656565" style="color: white; font-size: 90%">
<table>
<tr><td><pre>
<xsl:for-each select="/icestats"> <xsl:for-each select="log"> <xsl:value-of select="." /> </xsl:for-each></xsl:for-each>
Modified: icecast/branches/kh/icecast/config.h.vc6
===================================================================
--- icecast/branches/kh/icecast/config.h.vc6 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/config.h.vc6 2008-10-04 01:09:17 UTC (rev 15372)
@@ -13,7 +13,7 @@
/* Define to 1 if you have the <curl/curl.h> header file. */
#define HAVE_CURL_CURL_H 1
-/* Define t o1 if you have the 'curl_global_init' function */
+/* Define to 1 if you have the 'curl_global_init' function */
#define HAVE_CURL_GLOBAL_INIT 1
/* Define to 1 if you have the `inet_aton' function. */
@@ -95,7 +95,7 @@
#define PACKAGE_NAME "Icecast"
/* Version number of package */
-#define VERSION "2.3.2-kh1"
+#define VERSION "2.3.2-kh2"
/* Define to the version of this package. */
#define PACKAGE_VERSION VERSION
@@ -162,3 +162,4 @@
/* time format for strftime */
#define ICECAST_TIME_FMT "%a, %d %b %Y %H:%M:%S"
+#define PATH_MAX MAX_PATH
Modified: icecast/branches/kh/icecast/configure.in
===================================================================
--- icecast/branches/kh/icecast/configure.in 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/configure.in 2008-10-04 01:09:17 UTC (rev 15372)
@@ -1,4 +1,4 @@
-AC_INIT([Icecast], [2.3.2-kh1], [karl at xiph.org])
+AC_INIT([Icecast], [2.3.2-kh2], [karl at xiph.org])
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(src/main.c)
@@ -155,7 +155,7 @@
AC_SUBST(HAVE_KATE)
AC_SUBST(KATE_LIBS)
-AC_OUTPUT([Makefile conf/Makefile debian/Makefile src/Makefile src/avl/Makefile
+AC_OUTPUT([Makefile conf/Makefile src/Makefile src/avl/Makefile
src/httpp/Makefile src/thread/Makefile src/log/Makefile
src/net/Makefile src/timing/Makefile doc/Makefile web/Makefile web/images/Makefile
admin/Makefile win32/Makefile win32/res/Makefile])
Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/admin.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -58,6 +58,7 @@
static void command_manageauth(client_t *client, source_t *source,
int response);
static void command_buildm3u(client_t *client, const char *mount);
+static void command_show_image (client_t *client, const char* mount);
static void command_kill_source(client_t *client, source_t *source,
int response);
static void command_updatemetadata(client_t *client, source_t *source,
@@ -355,6 +356,11 @@
command_buildm3u (client, mount);
return 0;
}
+ if (strcmp (uri, "showimage") == 0)
+ {
+ command_show_image (client, mount);
+ return 0;
+ }
/* This is a mount request, but admin user is allowed */
if (client->authenticated == 0)
@@ -763,6 +769,29 @@
xmlFreeDoc(doc);
}
+static void command_show_image (client_t *client, const char *mount)
+{
+ source_t *source;
+
+ avl_tree_rlock (global.source_tree);
+ source = source_find_mount_raw (mount);
+ if (source && source->format && source->format->get_image)
+ {
+ thread_mutex_lock (&source->lock);
+ avl_tree_unlock (global.source_tree);
+ if (source->format->get_image (client, source->format) == 0)
+ {
+ thread_mutex_unlock (&source->lock);
+ fserve_add_client (client, NULL);
+ return;
+ }
+ thread_mutex_unlock (&source->lock);
+ }
+ else
+ avl_tree_unlock (global.source_tree);
+ client_send_404 (client, "No image available");
+}
+
static void command_buildm3u (client_t *client, const char *mount)
{
const char *username = NULL;
@@ -961,6 +990,7 @@
format_plugin_t *plugin;
xmlDocPtr doc;
xmlNodePtr node;
+ int same_ip = 1;
doc = xmlNewDoc(XMLSTR("1.0"));
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
@@ -977,10 +1007,13 @@
thread_mutex_lock (&source->lock);
plugin = source->format;
+ if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0)
+ if (response == RAW && connection_check_admin_pass (client->parser) == 0)
+ same_ip = 0;
do
{
- if (plugin == NULL)
+ if (same_ip == 0 && plugin == NULL)
break;
if (artwork)
stats_event (source->mount, "artwork", artwork);
@@ -1026,6 +1059,7 @@
{
const char *action;
const char *value;
+ int same_ip = 1;
DEBUG0("Got shoutcast metadata update request");
@@ -1046,6 +1080,10 @@
return;
}
+ if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0)
+ if (connection_check_admin_pass (client->parser) == 0)
+ same_ip = 0;
+
if (source->format && source->format->set_tag)
{
httpp_set_query_param (client->parser, "mount", client->server_conn->shoutcast_mount);
@@ -1084,7 +1122,7 @@
show_mount = httpp_get_query_param (client->parser, "mount");
- stats_get_xml(&doc, 1, show_mount);
+ stats_get_xml(&doc, STATS_ALL, show_mount);
admin_send_response (doc, client, response, filename);
xmlFreeDoc(doc);
}
Modified: icecast/branches/kh/icecast/src/auth_htpasswd.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_htpasswd.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/auth_htpasswd.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -108,6 +108,8 @@
char *sep;
char line [MAX_LINE_LEN];
+ if (htpasswd->filename == NULL)
+ return;
if (stat (htpasswd->filename, &file_stat) < 0)
{
WARN1 ("failed to check status of %s", htpasswd->filename);
Modified: icecast/branches/kh/icecast/src/cfgfile.h
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.h 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/cfgfile.h 2008-10-04 01:09:17 UTC (rev 15372)
@@ -132,6 +132,14 @@
int ssl;
};
+typedef struct
+{
+ char *hostname;
+ int port;
+ char *username;
+ char *password;
+} ice_master_details;
+
typedef struct ice_config_tag
{
char *config_filename;
@@ -169,6 +177,8 @@
listener_t *listen_sock;
unsigned int listen_sock_count;
+ ice_master_details *master;
+
char *master_server;
int master_server_port;
int master_update_interval;
Modified: icecast/branches/kh/icecast/src/connection.c
===================================================================
--- icecast/branches/kh/icecast/src/connection.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/connection.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -1129,7 +1129,7 @@
client->respcode = 200;
snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
- "HTTP/1.0 200 OK\r\n\r\n");
+ "HTTP/1.0 200 OK\r\ncapability: streamlist\r\n\r\n");
client->refbuf->len = strlen (client->refbuf->data);
fserve_add_client_callback (client, stats_callback, NULL);
}
Modified: icecast/branches/kh/icecast/src/format.c
===================================================================
--- icecast/branches/kh/icecast/src/format.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -378,4 +378,3 @@
return 0;
}
-
Modified: icecast/branches/kh/icecast/src/format.h
===================================================================
--- icecast/branches/kh/icecast/src/format.h 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format.h 2008-10-04 01:09:17 UTC (rev 15372)
@@ -53,6 +53,7 @@
void (*set_tag)(struct _format_plugin_tag *plugin, const char *tag, const char *value, const char *charset);
void (*free_plugin)(struct _format_plugin_tag *self);
void (*apply_settings)(client_t *client, struct _format_plugin_tag *format, struct _mount_proxy *mount);
+ int (*get_image)(client_t *client, struct _format_plugin_tag *format);
/* for internal state management */
void *_state;
Modified: icecast/branches/kh/icecast/src/format_kate.c
===================================================================
--- icecast/branches/kh/icecast/src/format_kate.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format_kate.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -38,12 +38,12 @@
typedef struct _kate_codec_tag
{
- int headers_done;
+ unsigned int headers_done;
#ifdef HAVE_KATE
kate_info ki;
kate_comment kc;
#endif
- int num_headers;
+ unsigned int num_headers;
int granule_shift;
ogg_int64_t last_iframe;
ogg_int64_t prev_granulepos;
Modified: icecast/branches/kh/icecast/src/format_mp3.c
===================================================================
--- icecast/branches/kh/icecast/src/format_mp3.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format_mp3.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -484,12 +484,12 @@
}
return 0;
}
+ rate_add (format->in_bitrate, bytes, global.time);
}
source_mp3->read_count += bytes;
refbuf = source_mp3->read_data;
refbuf->len = source_mp3->read_count;
format->read_bytes += bytes;
- rate_add (format->in_bitrate, bytes, global.time);
if (source_mp3->read_count < source_mp3->queue_block_size)
{
@@ -586,7 +586,6 @@
sizeof (source_mp3->build_metadata));
source_mp3->build_metadata_offset = 0;
source_mp3->build_metadata_len = 1 + (*src * 16);
- rate_add (plugin->in_bitrate, source_mp3->build_metadata_len, global.time);
}
/* do we have all of the metatdata block */
Modified: icecast/branches/kh/icecast/src/format_ogg.c
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format_ogg.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -54,6 +54,7 @@
static int create_ogg_client_data(source_t *source, client_t *client);
static void free_ogg_client_data (client_t *client);
+static int get_image (client_t *client, struct _format_plugin_tag *format);
static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf);
static refbuf_t *ogg_get_buffer (source_t *source);
static int write_buf_to_client (client_t *client);
@@ -152,8 +153,7 @@
while (codec)
{
ogg_codec_t *next = codec->next;
- if (codec->possible_start)
- refbuf_release (codec->possible_start);
+ refbuf_release (codec->possible_start);
codec->codec_free (ogg_info, codec);
codec = next;
}
@@ -177,6 +177,7 @@
plugin->write_buf_to_file = write_ogg_to_file;
plugin->create_client_data = create_ogg_client_data;
plugin->free_plugin = format_ogg_free_plugin;
+ plugin->get_image = get_image;
plugin->set_tag = NULL;
plugin->apply_settings = apply_ogg_settings;
if (strcmp (httpp_getvar (source->parser, "content-type"), "application/x-ogg") == 0)
@@ -623,4 +624,25 @@
write_ogg_data (source, refbuf);
}
+static int get_image (client_t *client, struct _format_plugin_tag *format)
+{
+ const char *serialp = httpp_get_query_param (client->parser, "serial");
+ ogg_state_t *ogg_info = format->_state;
+ ogg_codec_t *codec = ogg_info->codecs;
+ long serial;
+ if (serialp)
+ serial = atoll (serialp);
+ while (codec)
+ {
+ if (serialp == NULL || serial == codec->os.serialno)
+ {
+ int ret = 0;
+ if (codec->get_image)
+ ret = codec->get_image (client, codec);
+ return ret;
+ }
+ codec = codec->next;
+ }
+ return 0;
+}
Modified: icecast/branches/kh/icecast/src/format_ogg.h
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.h 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format_ogg.h 2008-10-04 01:09:17 UTC (rev 15372)
@@ -65,6 +65,7 @@
refbuf_t *(*process_page)(ogg_state_t *ogg_info,
struct ogg_codec_tag *codec, ogg_page *page);
void (*codec_free)(ogg_state_t *ogg_info, struct ogg_codec_tag *codec);
+ int (*get_image)(client_t *client, struct ogg_codec_tag *codec);
} ogg_codec_t;
Modified: icecast/branches/kh/icecast/src/format_theora.c
===================================================================
--- icecast/branches/kh/icecast/src/format_theora.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/format_theora.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -31,8 +31,21 @@
#define CATMODULE "format-theora"
#include "logging.h"
+#ifdef WITH_VIDEO_PREVIEW
+#include <png.h>
+typedef struct _video_preview_struct
+{
+ png_byte* rgb_image ;
+ int png_compression_level ;
+ int video_width ;
+ int video_height ;
+ int x_crop_offset ;
+ int y_crop_offset ;
+} video_preview_t;
+#endif
+
typedef struct _theora_codec_tag
{
theora_info ti;
@@ -40,9 +53,255 @@
int granule_shift;
ogg_int64_t last_iframe;
ogg_int64_t prev_granulepos;
+#ifdef WITH_VIDEO_PREVIEW
+ theora_state td;
+ video_preview_t *video_preview;
+ int frame_count;
+#endif
} theora_codec_t;
+ /* video_preview.c
+ * Copyright 2005, Silvano Galliani aka kysucix <kysucix at dyne.org>
+ */
+
+
+#include "logging.h"
+
+
+#ifdef WITH_VIDEO_PREVIEW
+struct preview_details
+{
+ unsigned int total_length;
+ refbuf_t **last;
+};
+
+static void yuv2rgb (yuv_buffer *_yuv, video_preview_t *video_preview);
+static int clip (int x);
+
+
+static void user_write_data (png_structp png_ptr, png_bytep data, png_size_t length)
+{
+#define BUFFER_BLOCK_SZ 316*1024
+ struct preview_details *details = png_get_io_ptr (png_ptr);
+ unsigned int offset = 0;
+ int c = 0;
+
+ if (*details->last == NULL)
+ {
+ /* special case */
+ refbuf_t *r = refbuf_new (BUFFER_BLOCK_SZ);
+ r->len = 0;
+ *details->last = r;
+ c++;
+ }
+ while (length)
+ {
+ unsigned int amount;
+ refbuf_t *buffer = *details->last;
+ if (buffer->len == BUFFER_BLOCK_SZ)
+ {
+ refbuf_t *last = buffer;
+ buffer = refbuf_new (BUFFER_BLOCK_SZ);
+ buffer->len = 0;
+ last->next = buffer;
+ details->last = &last->next;
+ c++;
+ }
+ amount = BUFFER_BLOCK_SZ - buffer->len;
+ if (amount > length)
+ amount = length;
+ memcpy (buffer->data+buffer->len, data+offset, amount);
+ buffer->len += amount;
+ offset += amount;
+ length -= amount;
+ }
+ details->total_length += offset;
+}
+
+
+static void user_flush_data (png_structp png_ptr)
+{
+}
+
+static void user_error (png_structp png_ptr, png_const_charp c)
+{
+ longjmp (png_ptr->jmpbuf, 1);
+}
+
+
+void free_video_preview (video_preview_t *video_preview)
+{
+ DEBUG0 ("freeing video preview");
+ free (video_preview->rgb_image);
+ free (video_preview);
+}
+
+
+video_preview_t *init_video_preview (int width, int height, int _x_crop_offset, int _y_crop_offset)
+{
+ DEBUG0("init video preview");
+
+ video_preview_t *video_preview = calloc (1, sizeof (video_preview_t));
+
+ /* init structure */
+ video_preview -> rgb_image = NULL;
+ video_preview -> png_compression_level = Z_BEST_SPEED;
+
+ video_preview -> video_width = width;
+ video_preview -> video_height = height;
+ video_preview -> x_crop_offset = _x_crop_offset;
+ video_preview -> y_crop_offset = _y_crop_offset;
+
+ /* malloc rgb image */
+ video_preview -> rgb_image = (png_byte *)calloc (1, video_preview -> video_width * video_preview -> video_height * 4 );
+ if (video_preview->rgb_image == NULL)
+ {
+ ERROR0 ("Can't allocate memory for rgb_image");
+ free_video_preview (video_preview);
+ return NULL;
+ }
+ return video_preview;
+}
+
+
+static int write_video_preview (client_t *client, video_preview_t *video_preview)
+{
+ int i;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ struct preview_details preview;
+
+ preview.total_length = 0;
+ preview.last = &client->refbuf->next;
+
+ png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
+ if (png_ptr == NULL)
+ return -1;
+
+ info_ptr = png_create_info_struct (png_ptr);
+ if (info_ptr == NULL)
+ {
+ png_destroy_write_struct (&png_ptr, (png_infopp)NULL);
+ return -1;
+ }
+
+ if (setjmp (png_ptr->jmpbuf))
+ {
+ png_destroy_write_struct (&png_ptr, (png_infopp)NULL);
+ return -1;
+ }
+
+ png_set_error_fn (png_ptr, NULL, user_error, user_error);
+ png_set_write_fn (png_ptr, &preview, user_write_data, user_flush_data);
+
+ png_set_filter( png_ptr, 0, PNG_FILTER_NONE );
+
+ /* set the zlib compression level */
+ png_set_compression_level (png_ptr, video_preview->png_compression_level);
+
+ png_set_IHDR (png_ptr, info_ptr, video_preview->video_width , video_preview->video_height,
+ 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ png_write_info (png_ptr, info_ptr);
+ ERROR0("finished writing png header");
+
+ /* write image to hard disk */
+ for ( i = 0; i < video_preview -> video_height; i++)
+ png_write_row (png_ptr,
+ video_preview->rgb_image + i * (video_preview->video_width) * 4 );
+
+ png_write_end (png_ptr, info_ptr);
+ png_destroy_write_struct (&png_ptr, &info_ptr);
+
+ snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\n"
+ "Content-Length: %d\r\nContentType: image/png\r\n\r\n", preview.total_length);
+ client->refbuf->len = strlen (client->refbuf->data);
+ client->respcode = 200;
+
+ return 0;
+}
+
+
+static int get_image (client_t *client, struct ogg_codec_tag *codec)
+{
+ theora_codec_t *theora = codec->specific;
+ return write_video_preview (client, theora->video_preview);
+}
+
+
+/* ok it has to be optimized but for now it's clean, and it's ok ;) */
+static void yuv2rgb (yuv_buffer *_yuv, video_preview_t *video_preview)
+{
+ int i,j;
+ int crop_offset;
+
+ int y_offset;
+ int ypp_offset;
+ int uv_offset;
+
+ /* rgba surface pointer */
+ unsigned char *prgb;
+ yuv_buffer *yuv;
+
+ unsigned char y;
+ unsigned char ypp;
+ unsigned char u;
+ unsigned char v;
+
+ yuv = _yuv;
+
+ crop_offset = (video_preview -> x_crop_offset) +
+ (yuv -> y_stride) * (video_preview -> y_crop_offset);
+ prgb = (unsigned char *)video_preview -> rgb_image;
+
+ for (i = 0; i < video_preview -> video_height; i++ ) {
+ for ( j = 0; j < video_preview -> video_width / 2; j++ ) {
+
+ y_offset = yuv -> y_stride * i + j*2 + crop_offset;
+ ypp_offset = yuv -> y_stride * i + j*2 + crop_offset + 1;
+ uv_offset = yuv -> uv_stride * (i/2) + j + crop_offset;
+
+ y = *(yuv->y + y_offset);
+ ypp = *(yuv->y + ypp_offset);
+ u = *(yuv->u + uv_offset);
+ v = *(yuv->v + uv_offset);
+
+ /* R G B A */
+ *prgb = clip (y + 1.402f * (v-128)) ;
+ prgb++;
+ *prgb = clip (y - 0.34414f * (u-128) - 0.71414f * (v-128)) ;
+ prgb++;
+ *prgb = clip (y + 1.772 * (u-128)) ;
+ prgb++;
+ *prgb = 255;
+ prgb++;
+
+ /* R G B A */
+ *prgb = clip (ypp + 1.402f * (v-128)) ;
+ prgb++;
+ *prgb = clip (ypp - 0.34414f * (u-128) - 0.71414f * (v-128)) ;
+ prgb++;
+ *prgb = clip (ypp + 1.772 * (u-128)) ;
+ prgb++;
+ *prgb = 255;
+ prgb++;
+ }
+ }
+}
+
+static int clip (int x)
+{
+ if (x > 255)
+ return 255;
+ else if (x < 0)
+ return 0;
+ return x;
+}
+#endif
+
+
static void theora_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
{
theora_codec_t *theora = codec->specific;
@@ -52,6 +311,14 @@
stats_event (ogg_info->mount, "video_quality", NULL);
stats_event (ogg_info->mount, "frame_rate", NULL);
stats_event (ogg_info->mount, "frame_size", NULL);
+#ifdef WITH_VIDEO_PREVIEW
+ stats_event (ogg_info->mount, "video_preview", NULL);
+ if (theora->video_preview)
+ {
+ free_video_preview (theora->video_preview);
+ theora_clear (&theora->td);
+ }
+#endif
theora_info_clear (&theora->ti);
theora_comment_clear (&theora->tc);
ogg_stream_clear (&codec->os);
@@ -113,7 +380,30 @@
return NULL;
}
if (theora_packet_iskeyframe (&packet))
+ {
has_keyframe = 1;
+#ifdef WITH_VIDEO_PREVIEW
+ if (theora->video_preview)
+ {
+ if (theora->frame_count == -1)
+ {
+ theora_decode_init (&theora->td, &theora->ti);
+ theora->frame_count = 0;
+ }
+ if (theora->frame_count % 16)
+ theora->frame_count++;
+ else
+ {
+ yuv_buffer yuv;
+
+ theora_decode_packetin (&theora->td, &packet);
+ theora_decode_YUVout (&theora->td, &yuv);
+ yuv2rgb (&yuv, theora->video_preview);
+ theora->frame_count = 1;
+ }
+ }
+#endif
+ }
}
if (header_page)
{
@@ -126,8 +416,7 @@
if (granulepos != theora->prev_granulepos || granulepos == 0)
{
- if (codec->possible_start)
- refbuf_release (codec->possible_start);
+ refbuf_release (codec->possible_start);
refbuf_addref (refbuf);
codec->possible_start = refbuf;
}
@@ -182,6 +471,20 @@
codec->filtered = 1;
codec->name = "Theora";
+#ifdef WITH_VIDEO_PREVIEW
+ /* check for video_preview config and video_preview initialization */
+ if (1)
+ {
+ theora_info *ti = &theora_codec->ti;
+ theora_codec->video_preview = init_video_preview (ti->width, ti->height, ti->offset_x, ti->offset_y);
+ theora_codec->frame_count = -1;
+ codec->get_image = get_image;
+ stats_event_args (ogg_info->mount, "video_preview", "/admin/showimage?mount=%s&serial=%ld", ogg_info->mount, codec->os.serialno);
+ //theora_decode_init (&theora_codec->td, &theora_codec->ti);
+ // theora_codec->frame_count = -1;
+ }
+#endif
+
format_ogg_attach_header (codec, page);
if (codec->filtered == 0)
ogg_info->codec_sync = codec;
Modified: icecast/branches/kh/icecast/src/fserve.c
===================================================================
--- icecast/branches/kh/icecast/src/fserve.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/fserve.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -296,8 +296,9 @@
client_tree_changed = 1;
continue;
}
- client_set_queue (client, refbuf->next);
- refbuf = client->refbuf;
+ refbuf = refbuf->next;
+ refbuf_release (client->refbuf);
+ client->refbuf = refbuf;
bytes = refbuf->len;
}
refbuf->len = bytes;
Modified: icecast/branches/kh/icecast/src/global.c
===================================================================
--- icecast/branches/kh/icecast/src/global.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/global.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -45,8 +45,7 @@
global.source_tree = avl_tree_new(source_compare_sources, NULL);
thread_mutex_create("global", &_global_mutex);
thread_spin_create ("xyz", &global.spinlock);
- /* do a sampling based on 1/10ths of a second */
- global.out_bitrate = rate_setup (60);
+ global.out_bitrate = rate_setup (151, 1000);
}
void global_shutdown(void)
@@ -70,10 +69,8 @@
void global_add_bitrates (struct rate_calc *rate, unsigned long value)
{
- time_t t = (time_t)(global.time_ms/100);
-
thread_spin_lock (&global.spinlock);
- rate_add (rate, value, t);
+ rate_add (rate, value, global.time_ms);
thread_spin_unlock (&global.spinlock);
}
@@ -88,7 +85,7 @@
{
unsigned long v;
thread_spin_lock (&global.spinlock);
- v = rate_avg (rate)*10L;
+ v = rate_avg (rate);
thread_spin_unlock (&global.spinlock);
return v;
}
Modified: icecast/branches/kh/icecast/src/refbuf.c
===================================================================
--- icecast/branches/kh/icecast/src/refbuf.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/refbuf.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -35,7 +35,7 @@
{
}
-refbuf_t *refbuf_new(size_t size)
+refbuf_t *refbuf_new (unsigned int size)
{
refbuf_t *refbuf;
Modified: icecast/branches/kh/icecast/src/refbuf.h
===================================================================
--- icecast/branches/kh/icecast/src/refbuf.h 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/refbuf.h 2008-10-04 01:09:17 UTC (rev 15372)
@@ -35,7 +35,7 @@
void refbuf_initialize(void);
void refbuf_shutdown(void);
-refbuf_t *refbuf_new(size_t size);
+refbuf_t *refbuf_new(unsigned int size);
void refbuf_addref(refbuf_t *self);
void refbuf_release(refbuf_t *self);
Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/slave.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -1075,12 +1075,17 @@
update_from_master (config);
+ thread_mutex_lock (&(config_locks()->relay_lock));
cleanup_relays = update_relays (&global.relays, config->relay);
config_release_config();
}
+ else
+ thread_mutex_lock (&(config_locks()->relay_lock));
+
relay_check_streams (global.relays, cleanup_relays, skip_timer);
relay_check_streams (global.master_relays, NULL, skip_timer);
+ thread_mutex_unlock (&(config_locks()->relay_lock));
if (update_settings)
{
Modified: icecast/branches/kh/icecast/src/source.c
===================================================================
--- icecast/branches/kh/icecast/src/source.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/source.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -254,6 +254,8 @@
{
refbuf_t *to_go = p;
p = to_go->next;
+ if (to_go->_count > 1)
+ WARN1 ("buffer is %d", to_go->_count);
refbuf_release (to_go);
}
/* the source holds 2 references on the very latest so that one
@@ -434,9 +436,9 @@
unsigned long kbytes_read = source->bytes_read_since_update/1024;
source->format->sent_bytes += kbytes_sent*1024;
- stats_event_args (source->mount, "outgoing_bitrate", "%ld",
+ stats_event_args (source->mount, "outgoing_kbitrate", "%ld",
(8 * rate_avg (source->format->out_bitrate))/1000);
- stats_event_args (source->mount, "incoming_bitrate", "%ld", incoming_rate/1000);
+ stats_event_args (source->mount, "incoming_bitrate", "%ld", incoming_rate);
stats_event_args (source->mount, "total_bytes_read",
"%"PRIu64, source->format->read_bytes);
stats_event_args (source->mount, "total_bytes_sent",
@@ -682,7 +684,7 @@
total_written += bytes;
}
- rate_add (source->format->out_bitrate, total_written, global.time);
+ rate_add (source->format->out_bitrate, total_written, global.time_ms);
source->bytes_sent_since_update += total_written;
global_add_bitrates (global.out_bitrate, total_written);
@@ -778,7 +780,7 @@
}
stats_event_args (source->mount, "listeners", "%lu", source->listeners);
if (source->listeners == 0)
- rate_add (source->format->out_bitrate, 0, 0);
+ rate_reduce (source->format->out_bitrate, 0);
/* change of listener numbers, so reduce scope of global sampling */
global_reduce_bitrate_sampling (global.out_bitrate);
/* do we need to shutdown an on-demand relay */
@@ -874,8 +876,8 @@
thread_mutex_lock (&source->lock);
- source->format->in_bitrate = rate_setup (source->avg_bitrate_duration+1);
- source->format->out_bitrate = rate_setup (source->avg_bitrate_duration+1);
+ source->format->in_bitrate = rate_setup (source->avg_bitrate_duration+1, 1);
+ source->format->out_bitrate = rate_setup (120, 1000);
source->running = 1;
}
@@ -1212,10 +1214,17 @@
source->avg_bitrate_duration = 60;
/* needs a better mechanism, probably via a client_t handle */
+ free (source->dumpfilename);
+ source->dumpfilename = NULL;
if (mountinfo && mountinfo->dumpfile)
{
- free (source->dumpfilename);
- source->dumpfilename = strdup (mountinfo->dumpfile);
+ time_t now = time(NULL);
+ struct tm local;
+ char buffer[PATH_MAX];
+
+ localtime_r (&now, &local);
+ strftime (buffer, sizeof (buffer), mountinfo->dumpfile, &local);
+ source->dumpfilename = strdup (buffer);
}
/* handle changes in intro file setting */
if (source->intro_file)
@@ -1268,7 +1277,7 @@
/* skip if source is a fallback to file */
if (source->running && source->client == NULL)
{
- stats_event_hidden (source->mount, NULL, 1);
+ stats_event_hidden (source->mount, NULL, NULL, STATS_HIDDEN);
return;
}
/* set global settings first */
@@ -1294,13 +1303,6 @@
if (mountinfo)
{
- if (mountinfo->hidden)
- {
- stats_event_hidden (source->mount, NULL, 1);
- DEBUG0 ("hidden from public");
- }
- else
- stats_event_hidden (source->mount, NULL, 0);
if (mountinfo->on_connect)
DEBUG1 ("connect script \"%s\"", mountinfo->on_connect);
if (mountinfo->on_disconnect)
@@ -1309,12 +1311,21 @@
DEBUG1 ("fallback_when_full to %u", mountinfo->fallback_when_full);
DEBUG1 ("max listeners to %d", mountinfo->max_listeners);
stats_event_args (source->mount, "max_listeners", "%d", mountinfo->max_listeners);
+ stats_event_hidden (source->mount, "cluster_password", mountinfo->cluster_password, STATS_SLAVE);
+ if (mountinfo->hidden)
+ {
+ stats_event_hidden (source->mount, NULL, NULL, STATS_HIDDEN);
+ DEBUG0 ("hidden from public");
+ }
+ else
+ stats_event_hidden (source->mount, NULL, NULL, STATS_PUBLIC);
}
else
{
DEBUG0 ("max listeners is not specified");
stats_event (source->mount, "max_listeners", "unlimited");
- stats_event_hidden (source->mount, NULL, 0);
+ stats_event_hidden (source->mount, "cluster_password", NULL, STATS_SLAVE);
+ stats_event_hidden (source->mount, NULL, NULL, STATS_PUBLIC);
}
DEBUG1 ("public set to %d", source->yp_public);
DEBUG1 ("queue size to %u", source->queue_size_limit);
@@ -1459,7 +1470,7 @@
httpp_setvar (parser, "content-type", type);
free (type);
- stats_event_hidden (source->mount, NULL, 1);
+ stats_event_hidden (source->mount, NULL, NULL, STATS_HIDDEN);
source->yp_public = 0;
source->intro_file = file;
source->parser = parser;
@@ -1522,7 +1533,7 @@
}
else if (update_all)
{
- stats_event_hidden (mount->mountname, NULL, mount->hidden);
+ stats_event_hidden (mount->mountname, NULL, NULL, mount->hidden?STATS_HIDDEN:0);
stats_event_args (mount->mountname, "listenurl", "http://%s:%d%s",
config->hostname, config->port, mount->mountname);
stats_event (mount->mountname, "listeners", "0");
Modified: icecast/branches/kh/icecast/src/stats.c
===================================================================
--- icecast/branches/kh/icecast/src/stats.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/stats.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -53,7 +53,7 @@
#define STATS_EVENT_ADD 3
#define STATS_EVENT_SUB 4
#define STATS_EVENT_REMOVE 5
-#define STATS_EVENT_HIDDEN 6
+#define STATS_EVENT_HIDDEN 0x80
typedef struct _stats_node_tag
{
@@ -80,43 +80,47 @@
avl_tree *stats_tree;
} stats_source_t;
-typedef struct _event_queue_tag
-{
- volatile stats_event_t *head;
- volatile stats_event_t **tail;
-} event_queue_t;
-
-#define event_queue_init(qp) { (qp)->head = NULL; (qp)->tail = &(qp)->head; }
-
typedef struct _event_listener_tag
{
- event_queue_t queue;
- mutex_t mutex;
+ client_t *client;
int master;
+ int hidden_level;
char *source;
+ /* queue for unwritten stats to stats clients */
+ refbuf_t *queue, **queue_recent_p;
+ unsigned int content_len;
+
struct _event_listener_tag *next;
} event_listener_t;
+
+typedef struct _stats_tag
+{
+ avl_tree *global_tree;
+ avl_tree *source_tree;
+
+ /* list of listeners for stats */
+ event_listener_t *event_listeners, *listeners_removed;
+
+} stats_t;
+
static volatile int _stats_running = 0;
-static volatile int _stats_threads = 0;
static stats_t _stats;
static mutex_t _stats_mutex;
-static volatile event_listener_t *_event_listeners;
-
static int _compare_stats(void *a, void *b, void *arg);
static int _compare_source_stats(void *a, void *b, void *arg);
static int _free_stats(void *key);
static int _free_source_stats(void *key);
-static void _add_event_to_queue(stats_event_t *event, event_queue_t *queue);
static stats_node_t *_find_node(avl_tree *tree, const char *name);
static stats_source_t *_find_source(avl_tree *tree, const char *source);
-static void _free_event(stats_event_t *event);
-static stats_event_t *_get_event_from_queue (event_queue_t *queue);
static void process_event (stats_event_t *event);
+static void _add_stats_to_stats_client (event_listener_t *listener, const char *fmt, va_list ap);
+static void stats_listener_send (int flags, const char *fmt, ...);
+static void process_event_unlocked (stats_event_t *event);
/* simple helper function for creating an event */
@@ -125,8 +129,10 @@
event->source = (char *)source;
event->name = (char *)name;
event->value = (char *)value;
+ event->hidden = STATS_PUBLIC;
+ if (source) event->hidden |= STATS_SLAVE;
if (value)
- event->action = 0;
+ event->action = STATS_EVENT_SET;
else
event->action = STATS_EVENT_REMOVE;
}
@@ -134,76 +140,53 @@
void stats_initialize(void)
{
- _event_listeners = NULL;
+ if (_stats_running)
+ return;
/* set up global struct */
_stats.global_tree = avl_tree_new(_compare_stats, NULL);
_stats.source_tree = avl_tree_new(_compare_source_stats, NULL);
+ _stats.event_listeners = NULL;
+ _stats.listeners_removed = NULL;
+
/* set up global mutex */
thread_mutex_create("stats", &_stats_mutex);
- /* fire off the stats thread */
_stats_running = 1;
stats_event_time (NULL, "server_start");
/* global currently active stats */
- stats_event (NULL, "clients", "0");
- stats_event (NULL, "connections", "0");
- stats_event (NULL, "sources", "0");
- stats_event (NULL, "stats", "0");
+ stats_event_hidden (NULL, "clients", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "sources", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "stats", "0", STATS_COUNTERS);
stats_event (NULL, "listeners", "0");
/* global accumulating stats */
- stats_event (NULL, "client_connections", "0");
- stats_event (NULL, "source_client_connections", "0");
- stats_event (NULL, "source_relay_connections", "0");
- stats_event (NULL, "source_total_connections", "0");
- stats_event (NULL, "stats_connections", "0");
- stats_event (NULL, "listener_connections", "0");
- stats_event (NULL, "outgoing_kbitrate", "0");
+ stats_event_hidden (NULL, "client_connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "source_client_connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "source_relay_connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "source_total_connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "stats_connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "listener_connections", "0", STATS_COUNTERS);
+ stats_event_hidden (NULL, "outgoing_kbitrate", "0", STATS_COUNTERS);
}
void stats_shutdown(void)
{
- int n;
-
if(!_stats_running) /* We can't shutdown if we're not running. */
return;
- /* wait for thread to exit */
_stats_running = 0;
- /* wait for other threads to shut down */
- do {
- thread_sleep(300000);
- thread_mutex_lock(&_stats_mutex);
- n = _stats_threads;
- thread_mutex_unlock(&_stats_mutex);
- } while (n > 0);
- INFO0("stats thread finished");
-
- /* free the queues */
-
thread_mutex_destroy(&_stats_mutex);
avl_tree_free(_stats.source_tree, _free_source_stats);
avl_tree_free(_stats.global_tree, _free_stats);
}
-stats_t *stats_get_stats(void)
-{
- /* lock global stats
-
- copy stats
- unlock global stats
-
- return copied stats */
-
- return NULL;
-}
-
/* simple name=tag stat create/update */
void stats_event(const char *source, const char *name, const char *value)
{
@@ -259,29 +242,27 @@
/* make stat hidden (non-zero). name can be NULL if it applies to a whole
* source stats tree. */
-void stats_event_hidden (const char *source, const char *name, int hidden)
+void stats_event_hidden (const char *source, const char *name, const char *value, int hidden)
{
- const char *str = NULL;
stats_event_t event;
- if (hidden)
- str = "";
- build_event (&event, source, name, NULL);
- event.action = STATS_EVENT_HIDDEN;
+ build_event (&event, source, name, value);
+ event.hidden = hidden;
+ event.action |= STATS_EVENT_HIDDEN;
process_event (&event);
}
/* printf style formatting for stat create/update */
void stats_event_args(const char *source, char *name, char *format, ...)
{
- char buf[1024];
va_list val;
int ret;
+ char buf[1024];
if (name == NULL)
return;
va_start(val, format);
- ret = vsnprintf(buf, 1024, format, val);
+ ret = vsnprintf(buf, sizeof (buf), format, val);
va_end(val);
if (ret < 0 || (unsigned int)ret >= sizeof (buf))
@@ -420,38 +401,16 @@
return NULL;
}
-static stats_event_t *_copy_event(stats_event_t *event)
-{
- stats_event_t *copy = (stats_event_t *)calloc(1, sizeof(stats_event_t));
- if (event->source)
- copy->source = (char *)strdup(event->source);
- else
- copy->source = NULL;
- if (event->name)
- copy->name = (char *)strdup(event->name);
- if (event->value)
- copy->value = (char *)strdup(event->value);
- else
- copy->value = NULL;
- copy->hidden = event->hidden;
- copy->next = NULL;
- return copy;
-}
-
-
/* helper to apply specialised changes to a stats node */
static void modify_node_event (stats_node_t *node, stats_event_t *event)
{
if (node == NULL || event == NULL)
return;
- if (event->action == STATS_EVENT_HIDDEN)
+ if (event->action & STATS_EVENT_HIDDEN)
{
- if (event->value)
- node->hidden = 1;
- else
- node->hidden = 0;
- return;
+ node->hidden = event->hidden;
+ event->action &= ~STATS_EVENT_HIDDEN;
}
if (event->action != STATS_EVENT_SET)
{
@@ -483,7 +442,7 @@
static void process_global_event (stats_event_t *event)
{
- stats_node_t *node;
+ stats_node_t *node = NULL;
/* DEBUG3("global event %s %s %d", event->name, event->value, event->action); */
if (event->action == STATS_EVENT_REMOVE)
@@ -491,16 +450,18 @@
/* we're deleting */
node = _find_node(_stats.global_tree, event->name);
if (node != NULL)
+ {
+ stats_listener_send (node->hidden, "DELETE global %s\n", event->name);
avl_delete(_stats.global_tree, (void *)node, _free_stats);
+ }
return;
}
node = _find_node(_stats.global_tree, event->name);
if (node)
{
modify_node_event (node, event);
- DEBUG3 ("update node on %s \"%s\" (%s)",
- event->source ? event->source : "global",
- node->name, node->value);
+ stats_listener_send (node->hidden, "EVENT global %s %s\n", node->name, node->value);
+ DEBUG2 ("update node on global \"%s\" (%s)", node->name, node->value);
}
else
{
@@ -508,8 +469,10 @@
node = (stats_node_t *)calloc(1, sizeof(stats_node_t));
node->name = (char *)strdup(event->name);
node->value = (char *)strdup(event->value);
+ node->hidden = event->hidden;
avl_insert(_stats.global_tree, (void *)node);
+ stats_listener_send (node->hidden, "EVENT global %s %s\n", event->name, event->value);
}
}
@@ -517,6 +480,8 @@
static void process_source_event (stats_event_t *event)
{
stats_source_t *snode = _find_source(_stats.source_tree, event->source);
+ stats_node_t *node = NULL;
+
if (snode == NULL)
{
if (event->action == STATS_EVENT_REMOVE)
@@ -527,16 +492,13 @@
DEBUG1 ("new source stat %s", event->source);
snode->source = (char *)strdup(event->source);
snode->stats_tree = avl_tree_new(_compare_stats, NULL);
- if (event->action == STATS_EVENT_HIDDEN)
- snode->hidden = 1;
- else
- snode->hidden = 0;
+ snode->hidden = STATS_SLAVE|STATS_GENERAL|STATS_HIDDEN;
avl_insert(_stats.source_tree, (void *)snode);
}
if (event->name)
{
- stats_node_t *node = _find_node(snode->stats_tree, event->name);
+ node = _find_node (snode->stats_tree, event->name);
if (node == NULL)
{
if (event->action == STATS_EVENT_REMOVE)
@@ -548,8 +510,11 @@
node = (stats_node_t *)calloc(1,sizeof(stats_node_t));
node->name = (char *)strdup(event->name);
node->value = (char *)strdup(event->value);
- node->hidden = snode->hidden;
+ node->hidden = event->hidden;
+ if (snode->hidden | STATS_HIDDEN)
+ node->hidden |= STATS_HIDDEN;
+ stats_listener_send (node->hidden, "EVENT %s %s %s\n", event->source, event->name, event->value);
avl_insert(snode->stats_tree, (void *)node);
}
return;
@@ -557,24 +522,42 @@
if (event->action == STATS_EVENT_REMOVE)
{
DEBUG1 ("delete node %s", event->name);
+ stats_listener_send (node->hidden, "DELETE %s %s\n", event->source, event->name);
avl_delete(snode->stats_tree, (void *)node, _free_stats);
return;
}
modify_node_event (node, event);
return;
}
- if (event->action == STATS_EVENT_HIDDEN)
+ /* change source hidden status */
+ if (event->action & STATS_EVENT_HIDDEN)
{
avl_node *node = avl_get_first (snode->stats_tree);
+ int visible = 0;
- if (event->value)
- snode->hidden = 1;
+ if ((event->hidden&STATS_HIDDEN) == (snode->hidden&STATS_HIDDEN))
+ return;
+ if (snode->hidden & STATS_HIDDEN)
+ {
+ snode->hidden &= ~STATS_HIDDEN;
+ stats_listener_send (snode->hidden, "NEW %s\n", snode->source);
+ visible = 1;
+ }
else
- snode->hidden = 0;
+ {
+ stats_listener_send (snode->hidden, "DELETE %s\n", snode->source);
+ snode->hidden |= STATS_HIDDEN;
+ }
while (node)
{
stats_node_t *stats = (stats_node_t*)node->key;
- stats->hidden = snode->hidden;
+ if (visible)
+ {
+ stats->hidden &= ~STATS_HIDDEN;
+ stats_listener_send (stats->hidden, "EVENT %s %s %s\n", snode->source, stats->name, stats->value);
+ }
+ else
+ stats->hidden |= STATS_HIDDEN;
node = avl_get_next (node);
}
return;
@@ -582,6 +565,7 @@
if (event->action == STATS_EVENT_REMOVE)
{
DEBUG1 ("delete source node %s", event->source);
+ stats_listener_send (snode->hidden, "DELETE %s\n", event->source);
avl_delete(_stats.source_tree, (void *)snode, _free_source_stats);
}
}
@@ -595,39 +579,98 @@
localtime_r (&now, &local);
strftime (buffer, sizeof (buffer), ICECAST_TIME_FMT, &local);
- stats_event (mount, name, buffer);
+ stats_event_hidden (mount, name, buffer, STATS_GENERAL);
}
-void stats_listener_send (stats_event_t *event)
+
+static void stats_listeners_send (event_listener_t *listener)
{
- event_listener_t *listener = (event_listener_t *)_event_listeners;
+ int loop = 6;
+ int ret;
+ client_t *client = listener->client;
- while (listener)
+ while (loop)
{
- int send_it = 1;
+ if (format_advance_queue (NULL, client) < 0)
+ break;
+ ret = format_generic_write_to_client (client);
+ if (ret < 0)
+ break;
+ listener->content_len -= ret;
+ loop--;
+ }
+}
- if (event->source && listener->source &&
- strcmp (event->source, listener->source) != 0)
- send_it = 0;
+static void clear_stats_queue (event_listener_t *listener)
+{
+ while (listener->queue && listener->queue->_count == 1)
+ {
+ refbuf_t *to_go = listener->queue;
+ listener->queue = to_go->next;
+ refbuf_release (to_go);
+ }
+}
- if (send_it)
+
+static void stats_listener_send (int hidden_level, const char *fmt, ...)
+{
+ va_list ap;
+ event_listener_t *listener = _stats.event_listeners,
+ **trail = &_stats.event_listeners;
+
+ va_start(ap, fmt);
+
+ while (listener)
+ {
+ client_t *client = listener->client;
+
+ if (listener->hidden_level & hidden_level)
{
- stats_event_t *copy = _copy_event(event);
- thread_mutex_lock (&listener->mutex);
- _add_event_to_queue (copy, &listener->queue);
- thread_mutex_unlock (&listener->mutex);
+ _add_stats_to_stats_client (listener, fmt, ap);
}
+ stats_listeners_send (listener);
+ if (client->con->error || listener->content_len > 10000)
+ {
+ stats_event_t stats_count;
+ char buffer [20];
+ *trail = listener->next;
+
+ build_event (&stats_count, NULL, "stats_connections", buffer);
+ stats_count.action = STATS_EVENT_DEC;
+ process_event_unlocked (&stats_count);
+
+ /* moved this listener so that final cleanup can be done outside of lock */
+ listener->next = _stats.listeners_removed;
+ _stats.listeners_removed = listener;
+
+ listener = *trail;
+ continue;
+ }
+ /* reduce queue if unsued */
+ clear_stats_queue (listener);
+
+ trail = &listener->next;
listener = listener->next;
}
+ va_end(ap);
}
void stats_global (ice_config_t *config)
{
- stats_event (NULL, "server_id", config->server_id);
- stats_event (NULL, "host", config->hostname);
+ stats_event_hidden (NULL, "server_id", config->server_id, STATS_GENERAL);
+ stats_event_hidden (NULL, "host", config->hostname, STATS_GENERAL);
stats_event (NULL, "location", config->location);
stats_event (NULL, "admin", config->admin);
+#if 0
+ /* restart a master stats connection */
+ config->master = calloc (1, sizeof ice_master_details);
+ config->master->hostname = xmlCharStrdup ("127.0.0.1");
+ config->master->port = 8000;
+ config->master->username = xmlCharStrdup ("relay");
+ config->master->password = xmlCharStrdup ("relayme");
+ _stats.sock = sock_connect_wto_bind (server, port, bind, 10);
+#endif
}
static void process_event_unlocked (stats_event_t *event)
@@ -637,10 +680,6 @@
process_global_event (event);
else
process_source_event (event);
-
- /* now we have an event that's been processed into the running stats */
- /* this event should get copied to event listeners' queues */
- stats_listener_send (event);
}
static void process_event (stats_event_t *event)
@@ -652,300 +691,230 @@
thread_mutex_unlock (&_stats_mutex);
}
-/* you must have the _stats_mutex locked here */
-static void _unregister_listener(event_listener_t *listener)
+
+static int _append_to_bufferv (refbuf_t *refbuf, int max_len, const char *fmt, va_list ap)
{
- event_listener_t **prev = (event_listener_t **)&_event_listeners,
- *current = *prev;
- stats_event_t stats_count, *event;
- char buffer [VAL_BUFSIZE];
+ char *buf = (char*)refbuf->data + refbuf->len;
+ int len = max_len - refbuf->len;
+ int ret;
+ va_list vl;
- while (current)
- {
- if (current == listener)
- {
- *prev = current->next;
- break;
- }
- prev = ¤t->next;
- current = *prev;
- }
-
- /* remove this listener before sending this change */
- build_event (&stats_count, NULL, "stats_connections", buffer);
- stats_count.action = STATS_EVENT_DEC;
- process_event_unlocked (&stats_count);
-
- /* flush any extra that sneaked on at the last moment */
- while ((event = _get_event_from_queue (&listener->queue)) != NULL)
- _free_event (event);
+ va_copy (vl, ap);
+ ret = vsnprintf (buf, len, fmt, vl);
+ if (ret < 0 || ret >= len)
+ return -1;
+ refbuf->len += ret;
+ return 0;
}
-
-static stats_event_t *_make_event_from_node(stats_node_t *node, char *source)
+static int _append_to_buffer (refbuf_t *refbuf, int max_len, const char *fmt, ...)
{
- stats_event_t *event = (stats_event_t *)malloc(sizeof(stats_event_t));
-
- if (source != NULL)
- event->source = (char *)strdup(source);
- else
- event->source = NULL;
- event->name = (char *)strdup(node->name);
- event->value = (char *)strdup(node->value);
- event->hidden = node->hidden;
- event->action = STATS_EVENT_SET;
- event->next = NULL;
+ int ret;
+ va_list va;
- return event;
+ va_start (va, fmt);
+ ret = _append_to_bufferv (refbuf, max_len, fmt, va);
+ va_end(va);
+ return ret;
}
-static void _add_event_to_queue(stats_event_t *event, event_queue_t *queue)
+static void _add_node_to_stats_client (event_listener_t *listener, refbuf_t *refbuf)
{
- *queue->tail = event;
- queue->tail = (volatile stats_event_t **)&event->next;
+ *listener->queue_recent_p = refbuf;
+ listener->queue_recent_p = &refbuf->next;
+ listener->content_len += refbuf->len;
}
-static stats_event_t *_get_event_from_queue (event_queue_t *queue)
+static void _add_stats_to_stats_client (event_listener_t *listener,const char *fmt, va_list ap)
{
- stats_event_t *event = NULL;
-
- if (queue && queue->head)
+ unsigned int size = 50;
+ while (size < 300)
{
- event = (stats_event_t *)queue->head;
- queue->head = event->next;
- if (queue->head == NULL)
- queue->tail = &queue->head;
- }
+ refbuf_t *refbuf = refbuf_new (size);
+ refbuf->len = 0;
- return event;
-}
-
-static int _send_event_to_client(stats_event_t *event, client_t *client)
-{
- int len;
- char buf [200];
-
- /* send data to the client!!!! */
- len = snprintf (buf, sizeof (buf), "EVENT %s %s %s\n",
- (event->source != NULL) ? event->source : "global",
- event->name ? event->name : "null",
- event->value ? event->value : "null");
- if (len > 0 && len < (int)sizeof (buf))
- {
- client_send_bytes (client, buf, len);
- if (client->con->error)
- return -1;
+ if (_append_to_bufferv (refbuf, size, fmt, ap) == 0)
+ {
+ _add_node_to_stats_client (listener, refbuf);
+ return;
+ }
+ refbuf_release (refbuf);
+ size += 100;
}
- return 0;
}
-void _dump_stats_to_queue (event_queue_t *queue)
+
+static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden)
{
- avl_node *node;
- avl_node *node2;
- stats_event_t *event;
- stats_source_t *source;
+ avl_node *avlnode;
+ xmlNodePtr ret = NULL;
thread_mutex_lock(&_stats_mutex);
- /* first we fill our queue with the current stats */
- /* start with the global stats */
- node = avl_get_first(_stats.global_tree);
- while (node) {
- event = _make_event_from_node((stats_node_t *)node->key, NULL);
- _add_event_to_queue(event, queue);
-
- node = avl_get_next(node);
+ /* general stats first */
+ avlnode = avl_get_first(_stats.global_tree);
+ while (avlnode)
+ {
+ stats_node_t *stat = avlnode->key;
+ if (stat->hidden & hidden)
+ xmlNewTextChild (root, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
+ avlnode = avl_get_next (avlnode);
}
+ /* now per mount stats */
+ avlnode = avl_get_first(_stats.source_tree);
+ while (avlnode)
+ {
+ stats_source_t *source = (stats_source_t *)avlnode->key;
+ if (source->hidden & hidden &&
+ (show_mount == NULL || strcmp (show_mount, source->source) == 0))
+ {
+ avl_node *avlnode2 = avl_get_first (source->stats_tree);
+ xmlNodePtr xmlnode = xmlNewTextChild (root, NULL, XMLSTR("source"), NULL);
- /* now the stats for each source */
- node = avl_get_first(_stats.source_tree);
- while (node) {
- source = (stats_source_t *)node->key;
- node2 = avl_get_first(source->stats_tree);
- while (node2) {
- event = _make_event_from_node((stats_node_t *)node2->key, source->source);
- _add_event_to_queue(event, queue);
-
- node2 = avl_get_next(node2);
+ xmlSetProp (xmlnode, XMLSTR("mount"), XMLSTR(source->source));
+ if (ret == NULL)
+ ret = xmlnode;
+ while (avlnode2)
+ {
+ stats_node_t *stat = avlnode2->key;
+ xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
+ avlnode2 = avl_get_next (avlnode2);
+ }
}
-
- node = avl_get_next(node);
+ avlnode = avl_get_next (avlnode);
}
thread_mutex_unlock(&_stats_mutex);
+ return ret;
}
+
/* factoring out code for stats loops
** this function copies all stats to queue, and registers
-** the queue for all new events atomically.
-** note: mutex must already be created!
*/
static void _register_listener (event_listener_t *listener)
{
avl_node *node;
- avl_node *node2;
- stats_event_t *event;
- stats_source_t *source;
stats_event_t stats_count;
+ refbuf_t *refbuf;
+ size_t size = 8192;
char buffer[20];
build_event (&stats_count, NULL, "stats_connections", buffer);
stats_count.action = STATS_EVENT_INC;
process_event_unlocked (&stats_count);
- /* first we fill our queue with the current stats */
-
- /* start with the global stats */
- node = avl_get_first(_stats.global_tree);
- while (node) {
- event = _make_event_from_node((stats_node_t *)node->key, NULL);
- _add_event_to_queue (event, &listener->queue);
+ while (size < 50000) /* use a large limit */
+ {
+ /* first we fill our queue with the current stats */
+ refbuf = refbuf_new (size);
+ refbuf->len = 0;
- node = avl_get_next(node);
- }
+ /* starts with the http response header */
+ if (_append_to_buffer (refbuf, size, "HTTP/1.0 200 OK\r\ncapability: streamlist\r\n\r\n") < 0)
+ {
+ refbuf_release (refbuf);
+ break;
+ }
+ /* now the global stats */
+ node = avl_get_first(_stats.global_tree);
+ while (node)
+ {
+ stats_node_t *stat = node->key;
- /* now the stats for each source */
- node = avl_get_first(_stats.source_tree);
- while (node) {
- source = (stats_source_t *)node->key;
- node2 = avl_get_first(source->stats_tree);
- while (node2) {
- event = _make_event_from_node((stats_node_t *)node2->key, source->source);
- _add_event_to_queue (event, &listener->queue);
-
- node2 = avl_get_next(node2);
+ node = avl_get_next(node);
+ if ((stat->hidden & listener->hidden_level) == 0)
+ continue;
+ if (_append_to_buffer (refbuf, size, "EVENT global %s %s\n", stat->name, stat->value) < 0)
+ {
+ size += 8192;
+ refbuf_release (refbuf);
+ break;
+ }
}
-
- node = avl_get_next(node);
- }
+ if (node) continue; /* catch buffer full case */
- /* now we register to receive future event notices */
- listener->next = (event_listener_t *)_event_listeners;
- _event_listeners = listener;
-}
-
-static void check_uri (event_listener_t *listener, client_t *client)
-{
- const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI);
- if (strcmp (mount, "/") != 0)
- listener->source = strdup (mount);
-}
-
-
-void *stats_connection(void *arg)
-{
- client_t *client = (client_t *)arg;
- stats_event_t *event;
- event_listener_t listener;
-
- INFO0 ("stats client starting");
-
- memset (&listener, 0, sizeof (listener));
- event_queue_init (&listener.queue);
- check_uri (&listener, client);
-
- /* increment the thread count */
- thread_mutex_lock(&_stats_mutex);
- _stats_threads++;
- thread_mutex_create("stats local event", &listener.mutex);
-
- _register_listener (&listener);
- thread_mutex_unlock(&_stats_mutex);
-
- while (_stats_running) {
- thread_mutex_lock (&listener.mutex);
- event = _get_event_from_queue (&listener.queue);
- thread_mutex_unlock (&listener.mutex);
- if (event != NULL) {
- if (_send_event_to_client(event, client) < 0) {
- _free_event(event);
+ /* now the stats for each source */
+ node = avl_get_first(_stats.source_tree);
+ while (node)
+ {
+ avl_node *node2;
+ stats_source_t *snode = (stats_source_t *)node->key;
+ node = avl_get_next(node);
+ if ((snode->hidden & listener->hidden_level) == 0)
+ continue;
+ if (_append_to_buffer (refbuf, size, "NEW %s\n", snode->source) < 0)
+ {
+ size += 8192;
+ refbuf_release (refbuf);
break;
}
- _free_event(event);
- continue;
+ node2 = avl_get_first(snode->stats_tree);
+ while (node2)
+ {
+ stats_node_t *stat = node2->key;
+ node2 = avl_get_next(node2);
+
+ if ((stat->hidden & listener->hidden_level) == 0)
+ continue;
+ if (_append_to_buffer (refbuf, size, "EVENT %s %s %s\n", snode->source, stat->name, stat->value) < 0)
+ {
+ size += 8192;
+ refbuf_release (refbuf);
+ break;
+ }
+ }
}
- thread_sleep (500000);
+ if (node) continue; /* catch buffer full case */
+ break;
}
- thread_mutex_lock(&_stats_mutex);
- _unregister_listener (&listener);
- _stats_threads--;
- thread_mutex_unlock(&_stats_mutex);
+ client_set_queue (listener->client, refbuf);
+ _add_node_to_stats_client (listener, refbuf);
- thread_mutex_destroy (&listener.mutex);
- free (listener.source);
- client_destroy (client);
- INFO0 ("stats client finished");
-
- return NULL;
+ /* now we register to receive future event notices */
+ listener->next = _stats.event_listeners;
+ _stats.event_listeners = listener;
}
-
-void stats_callback (client_t *client, void *notused)
+static void check_uri (event_listener_t *listener, const char *mount)
{
- if (client->con->error)
+ listener->hidden_level = STATS_PUBLIC;
+ if (strncmp (mount, "/admin/", 7) == 0)
{
- client_destroy (client);
- return;
+ if (strcmp (mount+7, "streams") == 0)
+ listener->hidden_level = STATS_SLAVE|STATS_GENERAL;
}
- client_set_queue (client, NULL);
- thread_create("Stats Connection", stats_connection, (void *)client, THREAD_DETACHED);
+ /* else
+ * check for reserved mountpoint, show hidden source stats */
}
-typedef struct _source_xml_tag {
- char *mount;
- xmlNodePtr node;
- struct _source_xml_tag *next;
-} source_xml_t;
-
-static xmlNodePtr _find_xml_node(const char *mount, source_xml_t **list, xmlNodePtr root)
+void stats_callback (client_t *client, void *arg)
{
- source_xml_t *node, *node2;
- int found = 0;
+ event_listener_t * listener;
+ const char *mount = arg;
- /* search for existing node */
- node = *list;
- while (node) {
- if (strcmp(node->mount, mount) == 0) {
- found = 1;
- break;
- }
- node = node->next;
- }
+ client_set_queue (client, NULL);
+ listener = calloc (1, sizeof (event_listener_t));
+ listener->client = client;
+ listener->queue_recent_p = &listener->queue;
+ check_uri (listener, mount);
- if (found) return node->node;
-
- /* if we didn't find it, we must build it and add it to the list */
-
- /* build node */
- node = (source_xml_t *)malloc(sizeof(source_xml_t));
- node->mount = strdup(mount);
- node->node = xmlNewChild(root, NULL, XMLSTR("source"), NULL);
- xmlSetProp(node->node, XMLSTR("mount"), XMLSTR(mount));
- node->next = NULL;
-
- /* add node */
- if (*list == NULL) {
- *list = node;
- } else {
- node2 = *list;
- while (node2->next) node2 = node2->next;
- node2->next = node;
- }
-
- return node->node;
+ thread_mutex_lock(&_stats_mutex);
+ _register_listener (listener);
+ thread_mutex_unlock(&_stats_mutex);
}
+
void stats_transform_xslt(client_t *client, const char *uri)
{
xmlDocPtr doc;
char *xslpath = util_get_path_from_normalised_uri (uri);
const char *mount = httpp_get_query_param (client->parser, "mount");
- stats_get_xml(&doc, 0, mount);
+ stats_get_xml(&doc, STATS_PUBLIC, mount);
xslt_transform(doc, xslpath, client);
@@ -953,71 +922,28 @@
free (xslpath);
}
-void stats_get_xml(xmlDocPtr *doc, int show_hidden, const char *show_mount)
+void stats_get_xml(xmlDocPtr *doc, int hidden, const char *show_mount)
{
- stats_event_t *event;
- event_queue_t queue;
- xmlNodePtr node, srcnode;
- source_xml_t *src_nodes = NULL;
- source_xml_t *next;
+ xmlNodePtr node;
- event_queue_init (&queue);
- _dump_stats_to_queue (&queue);
-
*doc = xmlNewDoc (XMLSTR("1.0"));
node = xmlNewDocNode (*doc, NULL, XMLSTR("icestats"), NULL);
xmlDocSetRootElement(*doc, node);
- event = _get_event_from_queue(&queue);
- while (event)
- {
- if (event->hidden <= show_hidden)
- {
- do
- {
- xmlChar *name, *value;
- if (event->source)
- {
- if (show_mount && strcmp (event->source, show_mount) != 0)
- break;
- srcnode = _find_xml_node(event->source, &src_nodes, node);
- }
- else
- srcnode = node;
+ node = _dump_stats_to_doc (node, show_mount, hidden);
- name = xmlEncodeEntitiesReentrant (*doc, XMLSTR(event->name));
- value = xmlEncodeEntitiesReentrant (*doc, XMLSTR(event->value));
- xmlNewChild(srcnode, NULL, name, value);
- xmlFree (value);
- xmlFree (name);
- } while (0);
- }
-
- _free_event(event);
- event = _get_event_from_queue(&queue);
- }
- if (show_mount)
- {
+ if (show_mount && node)
+ {
+ source_t *source;
/* show each listener */
- source_xml_t *src = src_nodes;
avl_tree_rlock (global.source_tree);
- while (src)
- {
- source_t *source = source_find_mount_raw (src->mount);
+ source = source_find_mount_raw (show_mount);
- if (source)
- admin_source_listeners (source, src->node);
+ if (source)
+ admin_source_listeners (source, node);
- src = src->next;
- }
avl_tree_unlock (global.source_tree);
}
- while (src_nodes) {
- next = src_nodes->next;
- free(src_nodes->mount);
- free(src_nodes);
- src_nodes = next;
- }
}
static int _compare_stats(void *arg, void *a, void *b)
@@ -1056,16 +982,7 @@
return 1;
}
-static void _free_event(stats_event_t *event)
-{
- if (event->source) free(event->source);
- if (event->name) free(event->name);
- if (event->value) free(event->value);
- free(event);
-}
-
-
/* return a list of blocks which contain lines of text. Each line is a mountpoint
* reference that a slave will use for relaying. The prepend setting is to indicate
* if some something else needs to be added to each line.
@@ -1149,19 +1066,35 @@
void stats_global_calc (void)
{
+ event_listener_t *listener;
+ static time_t next_update = 0;
stats_event_t event;
char buffer [VAL_BUFSIZE];
- static time_t next_update = 0;
if (global.time < next_update)
return;
- next_update = global.time + 1;
+
+ next_update = global.time + 2;
build_event (&event, NULL, "outgoing_kbitrate", buffer);
+ event.hidden = STATS_COUNTERS|STATS_HIDDEN;
thread_mutex_lock (&_stats_mutex);
snprintf (buffer, sizeof(buffer), "%" PRIu64,
- (int64_t)(global_getrate_avg (global.out_bitrate) * 8 / 1000.0 + 0.5));
+ (int64_t)global_getrate_avg (global.out_bitrate) * 8 / 1000);
process_event_unlocked (&event);
+ /* retrieve the list of closing down clients */
+ listener = _stats.listeners_removed;
+ _stats.listeners_removed = NULL;
thread_mutex_unlock (&_stats_mutex);
+
+ /* flush out any closed stats clients */
+ while (listener)
+ {
+ event_listener_t *to_go = listener;
+ listener = listener->next;
+ client_destroy (to_go->client);
+ clear_stats_queue (to_go);
+ free (to_go);
+ }
}
Modified: icecast/branches/kh/icecast/src/stats.h
===================================================================
--- icecast/branches/kh/icecast/src/stats.h 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/stats.h 2008-10-04 01:09:17 UTC (rev 15372)
@@ -21,36 +21,17 @@
#include <libxml/parser.h>
#include <libxml/tree.h>
+#define STATS_HIDDEN 1
+#define STATS_SLAVE 2
+#define STATS_GENERAL 4
+#define STATS_COUNTERS 8
+#define STATS_PUBLIC (STATS_GENERAL|STATS_COUNTERS)
+#define STATS_ALL ~0
-typedef struct _stats_tag
-{
- avl_tree *global_tree;
-
- /* global stats
- start_time
- total_users
- max_users
- total_sources
- max_sources
- total_user_connections
- total_source_connections
- */
-
- avl_tree *source_tree;
-
- /* stats by source, and for stats
- start_time
- total_users
- max_users
- */
-
-} stats_t;
-
void stats_initialize(void);
void stats_shutdown(void);
void stats_global(ice_config_t *config);
-stats_t *stats_get_stats(void);
void stats_get_streamlist (char *buffer, size_t remaining);
refbuf_t *stats_get_streams (int prepend);
void stats_clear_virtual_mounts (void);
@@ -63,11 +44,11 @@
void stats_event_add(const char *source, const char *name, unsigned long value);
void stats_event_sub(const char *source, const char *name, unsigned long value);
void stats_event_dec(const char *source, const char *name);
-void stats_event_hidden (const char *source, const char *name, int hidden);
+void stats_event_hidden (const char *source, const char *name, const char *value, int hidden);
void stats_event_time (const char *mount, const char *name);
void *stats_connection(void *arg);
-void stats_callback (client_t *client, void *notused);
+void stats_callback (client_t *client, void *mount);
void stats_global_calc(void);
void stats_transform_xslt(client_t *client, const char *uri);
Modified: icecast/branches/kh/icecast/src/util.c
===================================================================
--- icecast/branches/kh/icecast/src/util.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/util.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -47,18 +47,18 @@
struct rate_calc_node
{
- time_t time;
+ uint64_t index;
long value;
- struct rate_calc_node *next, *prev;
+ struct rate_calc_node *next;
};
struct rate_calc
{
uint64_t total;
- unsigned int seconds;
- unsigned int blocks;
- unsigned int recalc_total;
struct rate_calc_node *current;
+ unsigned int samples;
+ unsigned int ssec;
+ unsigned int blocks;
};
@@ -695,102 +695,90 @@
/* setup a rate block of so many seconds, so that an average can be
* determined of that range
*/
-struct rate_calc *rate_setup (unsigned int seconds)
+struct rate_calc *rate_setup (unsigned int samples, unsigned int ssec)
{
struct rate_calc *calc = calloc (1, sizeof (struct rate_calc));
- struct rate_calc_node *start = NULL;
- unsigned int i;
- if (calc == NULL || seconds == 0)
+ if (calc == NULL || samples < 2 || ssec == 0)
{
free (calc);
return NULL;
}
- for (i=0 ; i<seconds; i++)
- {
- struct rate_calc_node *node = calloc (1, sizeof (*node));
- if (calc->current)
- {
- calc->current->next = node;
- node->next = start;
- }
- else
- start = node;
- node->prev = calc->current;
- calc->current = node;
- }
- calc->current->next = start;
- start->prev = calc->current;
- calc->seconds = seconds;
+ calc->samples = samples;
+ calc->ssec = ssec;
return calc;
}
-/* */
-static void rate_recalc_total (struct rate_calc *calc)
-{
- int i;
- struct rate_calc_node *p = calc->current->prev;
- calc->total = 0;
- for (i=calc->blocks-1; i; i--)
- {
- calc->total += p->value;
- p = p->prev;
- }
-}
/* add a value to sampled data, t is used to determine which sample
* block the sample goes into.
*/
-void rate_add (struct rate_calc *calc, long value, time_t t)
+void rate_add (struct rate_calc *calc, long value, uint64_t sid)
{
- if (t == 0)
+ if (calc->current == NULL || sid != calc->current->index)
{
- calc->blocks = 0;
- return;
- }
- if (t != calc->current->time)
- {
- if (calc->recalc_total)
+ if (calc->blocks == calc->samples)
{
- /* here we keep the number of blocks and recalculate the total */
+ calc->total += calc->current->value;
calc->current = calc->current->next;
- rate_recalc_total (calc);
- calc->recalc_total--;
+ calc->total -= calc->current->value;
+ calc->current->value = value;
+ calc->current->index = sid;
+ return;
}
else
{
- /* common case */
- calc->total += calc->current->value;
- calc->current = calc->current->next;
- if (calc->blocks == calc->seconds)
- calc->total -= calc->current->value;
+ struct rate_calc_node *node = calloc (1, sizeof (*node));
+ node->index = sid;
+ calc->blocks++;
+ if (calc->current)
+ {
+ node->next = calc->current->next;
+ calc->current->next = node;
+ calc->total += calc->current->value;
+ }
else
- calc->blocks++;
+ {
+ node->next = node;
+ }
+ calc->current = node;
}
- calc->current->value = 0;
- calc->current->time = t;
}
calc->current->value += value;
}
-
/* return the average sample value over all the blocks except the
* current one, as that may be incomplete
*/
long rate_avg (struct rate_calc *calc)
{
+ uint64_t range;
+
if (calc == NULL || calc->blocks < 2)
return 0;
- return (long)(calc->total / (calc->blocks-1));
+ range = (calc->current->index - calc->current->next->index) / calc->ssec;
+ if (range < 1)
+ range = 1;
+ return (long)(calc->total / range);
}
/* reduce the samples used to calculate average */
-void rate_reduce (struct rate_calc *calc, unsigned long count)
+void rate_reduce (struct rate_calc *calc, unsigned int count)
{
- if (calc && count < calc->blocks && count >= 2)
+ if (calc && count < calc->blocks)
{
- calc->recalc_total = count*2;
- calc->blocks = count;
+ struct rate_calc_node *list = calc->current->next;
+ for (; calc->blocks > count; calc->blocks--)
+ {
+ struct rate_calc_node *to_go = list;
+ list = to_go->next;
+ calc->total -= to_go->value;
+ free (to_go);
+ }
+ if (calc->blocks)
+ calc->current->next = list;
+ else
+ calc->current = NULL;
}
}
Modified: icecast/branches/kh/icecast/src/util.h
===================================================================
--- icecast/branches/kh/icecast/src/util.h 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/util.h 2008-10-04 01:09:17 UTC (rev 15372)
@@ -58,11 +58,11 @@
#endif
char *util_conv_string (const char *string, const char *in_charset, const char *out_charset);
-struct rate_calc *rate_setup (unsigned int seconds);
-void rate_add (struct rate_calc *calc, long value, time_t t);
+struct rate_calc *rate_setup (unsigned int samples, unsigned int ssec);
+void rate_add (struct rate_calc *calc, long value, uint64_t t);
long rate_avg (struct rate_calc *calc);
void rate_free (struct rate_calc *calc);
-void rate_reduce (struct rate_calc *calc, unsigned long count);
+void rate_reduce (struct rate_calc *calc, unsigned int count);
int get_line(FILE *file, char *buf, size_t siz);
Modified: icecast/branches/kh/icecast/src/yp.c
===================================================================
--- icecast/branches/kh/icecast/src/yp.c 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/src/yp.c 2008-10-04 01:09:17 UTC (rev 15372)
@@ -925,12 +925,10 @@
void yp_touch (const char *mount)
{
struct yp_server *server = (struct yp_server *)active_yps;
- time_t trigger;
ypdata_t *search_list = NULL;
thread_rwlock_rlock (&yp_lock);
- /* do update in 3 secs, give stats chance to update */
- trigger = time(NULL) + 3;
+
if (server)
search_list = server->mounts;
@@ -945,9 +943,9 @@
search_list = yp->next;
continue;
}
- /* only force if touch */
- if (yp->process == do_yp_touch)
- yp->next_update = trigger;
+ /* don't update the directory if there is a touch scheduled soon */
+ if (yp->process == do_yp_touch && now + yp->touch_interval - yp->next_update > 60)
+ yp->next_update = now;
}
server = server->next;
if (server)
Modified: icecast/branches/kh/icecast/web/status.xsl
===================================================================
--- icecast/branches/kh/icecast/web/status.xsl 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/web/status.xsl 2008-10-04 01:09:17 UTC (rev 15372)
@@ -79,6 +79,17 @@
<xsl:if test="server_url">
<tr><td>Stream URL:</td><td class="streamdata"> <a target="_blank" href="{server_url}"><xsl:value-of select="server_url" /></a></td></tr>
</xsl:if>
+<xsl:if test="video_preview">
+<xsl:choose>
+<xsl:when test="authenticator">
+<tr><td>Preview:</td><td class="videopreview"> <a href="auth.xsl"><img src="{video_preview}" border="1" align="left" height="400" width="300" alt="frame preview" title="click to start watching the video!" /></a></td></tr>
+</xsl:when>
+<xsl:otherwise>
+<tr><td>Preview:</td><td class="videopreview"> <a href="{@mount}.m3u"><img src="{video_preview}" border="1" align="left" height="200" alt="frame preview" title="click to start watching the video!" /></a></td></tr>
+</xsl:otherwise>
+</xsl:choose>
+</xsl:if>
+
<tr><td>Current Song:</td><td class="streamdata">
<xsl:if test="artist"><xsl:value-of select="artist" /> - </xsl:if><xsl:value-of select="title" /></td></tr>
</table>
Modified: icecast/branches/kh/icecast/win32/icecast.dsp
===================================================================
--- icecast/branches/kh/icecast/win32/icecast.dsp 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/win32/icecast.dsp 2008-10-04 01:09:17 UTC (rev 15372)
@@ -363,10 +363,6 @@
# End Source File
# Begin Source File
-SOURCE=..\src\os.h
-# End Source File
-# Begin Source File
-
SOURCE=..\src\refbuf.h
# End Source File
# Begin Source File
Modified: icecast/branches/kh/icecast/win32/icecast2.iss
===================================================================
--- icecast/branches/kh/icecast/win32/icecast2.iss 2008-10-03 23:08:14 UTC (rev 15371)
+++ icecast/branches/kh/icecast/win32/icecast2.iss 2008-10-04 01:09:17 UTC (rev 15372)
@@ -3,7 +3,7 @@
[Setup]
AppName=Icecast2-KH
-AppVerName=Icecast v2.3.2-kh1
+AppVerName=Icecast v2.3.2-kh2
AppPublisherURL=http://www.icecast.org
AppSupportURL=http://www.icecast.org
AppUpdatesURL=http://www.icecast.org
@@ -13,7 +13,7 @@
LicenseFile=..\COPYING
InfoAfterFile=..\README
OutputDir=.
-OutputBaseFilename=icecast2_win32_v2.3.2-kh1_setup
+OutputBaseFilename=icecast2_win32_v2.3.2-kh2_setup
WizardImageFile=icecast2logo2.bmp
WizardImageStretch=no
; uncomment the following line if you want your installation to run on NT 3.51 too.
More information about the commits
mailing list