[SCM] ices2/master: Update patch 0001 to newer snapshot of upstream development: r18199 on 2012-02-13.
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue Mar 27 21:32:17 UTC 2012
The following commit has been merged in the master branch:
commit 9a03b52be4ee4a6864bf4f1a1fd8ef5c1fed23b4
Author: Jonas Smedegaard <dr at jones.dk>
Date: Tue Mar 27 22:35:33 2012 +0200
Update patch 0001 to newer snapshot of upstream development: r18199 on 2012-02-13.
diff --git a/debian/patches/0001_sync_20090819.patch b/debian/patches/0001_sync_20090819.patch
deleted file mode 100644
index 4dbd9d9..0000000
--- a/debian/patches/0001_sync_20090819.patch
+++ /dev/null
@@ -1,1293 +0,0 @@
-Description: Sync with upstream snapshot
-Origin: http://people.xiph.org/~brendan/snapshots/ices2/
---- a/configure.in
-+++ b/configure.in
-@@ -14,12 +14,6 @@
-
- dnl BSD headers break when _XOPEN_SOURCE is defined but without it seems
- dnl to be fine
--case "$host" in
-- *bsd*|*irix*)
-- ;;
-- *) AC_DEFINE(_XOPEN_SOURCE, 600, [Define if you have POSIX and XPG specifications])
-- ;;
--esac
- if test -n "$GCC"; then
- AC_DEFINE(_GNU_SOURCE, ,[Define if you have POSIX and GNU specifications])
- XIPH_VAR_APPEND([XIPH_CPPFLAGS], [-ffast-math -fsigned-char])
-@@ -52,7 +46,7 @@
-
- dnl Checks for header files.
- AC_HEADER_STDC
--AC_CHECK_HEADERS([stropts.h])
-+AC_CHECK_HEADERS([stropts.h sys/timeb.h sys/select.h])
-
- dnl Check for OSS
-
-@@ -91,6 +85,16 @@
- AC_DEFINE(HAVE_ALSA, ,[Define to enable ALSA input module])
- fi
-
-+dnl Check for RoarAudio
-+
-+AC_CHECK_HEADER(roaraudio.h, have_roaraudio=yes, have_roaraudio=no)
-+AM_CONDITIONAL(HAVE_ROARAUDIO,test "$have_roaraudio" = yes)
-+
-+if test "$have_roaraudio" = yes; then
-+ ROARAUDIO_LIBS="-lroar"
-+ AC_DEFINE(HAVE_ROARAUDIO, ,[Define to enable RoarAudio input module])
-+fi
-+
- dnl Checks for typedefs, structures, and compiler characteristics.
- AC_C_CONST
-
-@@ -99,6 +103,8 @@
-
- dnl Checks for library functions.
-
-+AC_CHECK_FUNCS([gettimeofday ftime])
-+
- XIPH_PATH_XML
- XIPH_VAR_APPEND([XIPH_CFLAGS], [$XML_CFLAGS])
- XIPH_VAR_PREPEND([XIPH_LIBS], [$XML_LIBS])
-@@ -120,6 +126,7 @@
- dnl Make substitutions
-
- AC_SUBST(ALSA_LIBS)
-+AC_SUBST(ROARAUDIO_LIBS)
- AC_SUBST(XML_LIBS)
- AC_SUBST(XML_CFLAGS)
- AC_SUBST(LIBTOOL_DEPS)
---- a/m4/ogg.m4
-+++ b/m4/ogg.m4
-@@ -15,7 +15,7 @@
- ogg_prefix="$withval",
- ogg_prefix="$OGG_PREFIX"
- )
--if test "x$ogg_prefix" = "x"; then
-+if test "x$ogg_prefix" = "x" -o "x$ogg_prefix" = "xyes"; then
- if test "x$prefix" = "xNONE"; then
- ogg_prefix=/usr/local
- else
---- a/m4/vorbis.m4
-+++ b/m4/vorbis.m4
-@@ -21,7 +21,7 @@
- vorbis_prefix="$withval",
- vorbis_prefix="$VORBIS_PREFIX"
- )
--if test "x$vorbis_prefix" = "x"; then
-+if test "x$vorbis_prefix" = "x" -o "x$vorbis_prefix" = "xyes"; then
- if test "x$prefix" = "xNONE"; then
- vorbis_prefix="/usr/local"
- else
-@@ -58,16 +58,17 @@
- )
- ])
-
--AC_MSG_RESULT([$xt_lib_vorbis])
- if test "x$xt_lib_vorbis" = "xok"; then
- #
- # Now check if the installed Vorbis is sufficiently new.
- #
--AC_CHECK_TYPES([struct ovectl_ratemanage_arg],,
-- [xt_lib_vorbis="old version found"], [
-+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
- #include <vorbis/codec.h>
- #include <vorbis/vorbisenc.h>
-- ])
-+ ], [
-+struct ovectl_ratemanage_arg a;
-+])],,[xt_lib_vorbis="old version found"])
-+AC_MSG_RESULT([$xt_lib_vorbis])
- fi
- CPPFLAGS="$xt_save_CPPFLAGS"
- LIBS="$xt_save_LIBS"
---- a/m4/xiph_compiler.m4
-+++ b/m4/xiph_compiler.m4
-@@ -178,9 +178,9 @@
- [ AH_TEMPLATE([__func__], [Replace __func__ if not supported])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[const char *x = __FUNCTION__;])],
- [ AC_DEFINE([__func__],[__FUNCTION__])
-- AC_MSG_RESULT([yes])],
-- [ AC_DEFINE([__func__],[""])
-- AC_MSG_RESULT([no])
-+ AC_MSG_RESULT([Using __FUNCTION__])],
-+ [ AC_DEFINE([__func__],["__FILE__"])
-+ AC_MSG_RESULT([using __FILE__])
- ])
- ])
- ])dnl XIPH_C__FUNC__
---- a/m4/xiph_xml2.m4
-+++ b/m4/xiph_xml2.m4
-@@ -52,7 +52,7 @@
- ac_xslt_save_CFLAGS="$CFLAGS"
- LIBS="$XSLT_LIBS $LIBS"
- CFLAGS="$CFLAGS $XSLT_CFLAGS"
--AC_CHECK_FUNC(xsltSaveResultToString,,[AC_MSG_ERROR([Unable to link with libxslt (>=v1.0.18)])])
-+AC_CHECK_FUNCS([xsltSaveResultToString])
- CFLAGS="$ac_xslt_save_CFLAGS"
- LIBS="$ac_xslt_save_LIBS"
- ])
---- a/src/avl/avl.c
-+++ b/src/avl/avl.c
-@@ -54,7 +54,9 @@
- node->rank_and_balance = 0;
- AVL_SET_BALANCE (node, 0);
- AVL_SET_RANK (node, 1);
-+#ifdef HAVE_AVL_NODE_LOCK
- thread_rwlock_create(&node->rwlock);
-+#endif
- return node;
- }
- }
-@@ -70,6 +72,7 @@
- } else {
- avl_node * root = avl_node_new((void *)NULL, (avl_node *) NULL);
- if (!root) {
-+ free (t);
- return NULL;
- } else {
- t->root = root;
-@@ -94,7 +97,9 @@
- if (node->right) {
- avl_tree_free_helper (node->right, free_key_fun);
- }
-+#ifdef HAVE_AVL_NODE_LOCK
- thread_rwlock_destroy (&node->rwlock);
-+#endif
- free (node);
- }
-
-@@ -105,7 +110,9 @@
- avl_tree_free_helper (tree->root->right, free_key_fun);
- }
- if (tree->root) {
-+#ifdef HAVE_AVL_NODE_LOCK
- thread_rwlock_destroy(&tree->root->rwlock);
-+#endif
- free (tree->root);
- }
- thread_rwlock_destroy(&tree->rwlock);
-@@ -449,7 +456,9 @@
- /* return the key and node to storage */
- if (free_key_fun)
- free_key_fun (x->key);
-+#ifdef HAVE_AVL_NODE_LOCK
- thread_rwlock_destroy (&x->rwlock);
-+#endif
- free (x);
-
- while (shorter && p->parent) {
-@@ -821,14 +830,14 @@
- /* search left */
- left = avl_get_prev (node);
- i = m;
-- while ((i > 0) && (tree->compare_fun (tree->compare_arg, key, left->key) == 0)) {
-+ while (left && (i > 0) && (tree->compare_fun (tree->compare_arg, key, left->key) == 0)) {
- left = avl_get_prev (left);
- i = i - 1;
- }
- /* search right */
- right = avl_get_next (node);
- j = m;
-- while ((j <= tree->length) && (tree->compare_fun (tree->compare_arg, key, right->key) == 0)) {
-+ while (right && (j <= tree->length) && (tree->compare_fun (tree->compare_arg, key, right->key) == 0)) {
- right = avl_get_next (right);
- j = j + 1;
- }
-@@ -869,7 +878,7 @@
- avl_node * left;
- /* search left */
- left = avl_get_prev (low_node);
-- while ((i > 0) && (tree->compare_fun (tree->compare_arg, low_key, left->key) == 0)) {
-+ while (left && (i > 0) && (tree->compare_fun (tree->compare_arg, low_key, left->key) == 0)) {
- left = avl_get_prev (left);
- i = i - 1;
- }
-@@ -880,7 +889,7 @@
- avl_node * right;
- /* search right */
- right = avl_get_next (high_node);
-- while ((j <= tree->length) && (tree->compare_fun (tree->compare_arg, high_key, right->key) == 0)) {
-+ while (right && (j <= tree->length) && (tree->compare_fun (tree->compare_arg, high_key, right->key) == 0)) {
- right = avl_get_next (right);
- j = j + 1;
- }
-@@ -1167,6 +1176,7 @@
- thread_rwlock_unlock(&tree->rwlock);
- }
-
-+#ifdef HAVE_AVL_NODE_LOCK
- void avl_node_rlock(avl_node *node)
- {
- thread_rwlock_rlock(&node->rwlock);
-@@ -1181,3 +1191,4 @@
- {
- thread_rwlock_unlock(&node->rwlock);
- }
-+#endif
---- a/src/avl/avl.h
-+++ b/src/avl/avl.h
-@@ -12,7 +12,7 @@
- #endif
-
- #ifndef NO_THREAD
--#include <thread/thread.h>
-+#include "thread/thread.h"
- #else
- #define thread_rwlock_create(x) do{}while(0)
- #define thread_rwlock_destroy(x) do{}while(0)
-@@ -31,8 +31,8 @@
- * factor: 00==-1, 01==0, 10==+1.
- * The rest of the bits are used for <rank>
- */
-- unsigned long rank_and_balance;
--#ifndef NO_THREAD
-+ unsigned int rank_and_balance;
-+#if !defined(NO_THREAD) && defined(HAVE_AVL_NODE_LOCK)
- rwlock_t rwlock;
- #endif
- } avl_node;
-@@ -92,8 +92,8 @@
-
- typedef struct _avl_tree {
- avl_node * root;
-- unsigned long height;
-- unsigned long length;
-+ unsigned int height;
-+ unsigned int length;
- avl_key_compare_fun_type compare_fun;
- void * compare_arg;
- #ifndef NO_THREAD
---- a/src/im_playlist.c
-+++ b/src/im_playlist.c
-@@ -167,12 +167,8 @@
- if (ogg_page_bos (&og))
- {
- if (ogg_page_serialno (&og) == pl->current_serial)
-- {
-- LOG_WARN1 ("Skipping \"%s\" as the serial number is the same as previous", pl->filename);
-- pl->nexttrack = 1;
-- pl->errors++;
-- return 0;
-- }
-+ LOG_WARN1 ("detected duplicate serial number reading \"%s\"", pl->filename);
-+
- pl->current_serial = ogg_page_serialno (&og);
- }
- if (input_calculate_ogg_sleep (&og) < 0)
---- /dev/null
-+++ b/src/im_roar.c
-@@ -0,0 +1,266 @@
-+/* im_oss.c
-+ * - Raw PCM/Ogg Vorbis input from RoarAudio
-+ *
-+ * Copyright (c) 2001 Michael Smith <msmith at labyrinth.net.au>
-+ * Copyright (c) 2009 Philipp Schafft <lion at lion.leolix.org>
-+ *
-+ * This program is distributed under the terms of the GNU General
-+ * Public License, version 2. You may use, modify, and redistribute
-+ * it under the terms of this license. A copy should be included
-+ * with this source.
-+ */
-+
-+#ifdef HAVE_CONFIG_H
-+ #include <config.h>
-+#endif
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <ogg/ogg.h>
-+#include <fcntl.h>
-+
-+
-+#include <thread/thread.h>
-+#include "cfgparse.h"
-+#include "stream.h"
-+#include "metadata.h"
-+#include "inputmodule.h"
-+
-+#include "im_roar.h"
-+
-+#define MODULE "input-roar/"
-+#include "logging.h"
-+
-+#define BUFSIZE 2048
-+
-+/* Some platforms (freebsd) don't define this, so just define it to something
-+ * that should be treated the same
-+ */
-+#ifndef ERESTART
-+#define ERESTART EINTR
-+#endif
-+
-+static void close_module(input_module_t *mod)
-+{
-+ if(mod)
-+ {
-+ if(mod->internal)
-+ {
-+ im_roar_state *s = mod->internal;
-+
-+ if(s->fd >= 0)
-+ close(s->fd);
-+
-+
-+ thread_mutex_destroy(&s->metadatalock);
-+ free(s);
-+
-+ roar_disconnect(&s->con);
-+ }
-+ free(mod);
-+ }
-+}
-+
-+static int event_handler(input_module_t *mod, enum event_type ev, void *param)
-+{
-+ im_roar_state *s = mod->internal;
-+
-+ switch(ev)
-+ {
-+ case EVENT_SHUTDOWN:
-+ close_module(mod);
-+ break;
-+ case EVENT_NEXTTRACK:
-+ s->newtrack = 1;
-+ break;
-+ case EVENT_METADATAUPDATE:
-+ thread_mutex_lock(&s->metadatalock);
-+ if(s->metadata)
-+ {
-+ char **md = s->metadata;
-+ while(*md)
-+ free(*md++);
-+ free(s->metadata);
-+ }
-+ s->metadata = (char **)param;
-+ s->newtrack = 1;
-+ thread_mutex_unlock(&s->metadatalock);
-+ break;
-+ default:
-+ LOG_WARN1("Unhandled event %d", ev);
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+static void metadata_update(void *self, vorbis_comment *vc)
-+{
-+ im_roar_state *s = self;
-+ char **md;
-+
-+ thread_mutex_lock(&s->metadatalock);
-+
-+ md = s->metadata;
-+
-+ if(md)
-+ {
-+ while(*md)
-+ vorbis_comment_add(vc, *md++);
-+ }
-+
-+ thread_mutex_unlock(&s->metadatalock);
-+}
-+
-+/* Core streaming function for this module
-+ * This is what actually produces the data which gets streamed.
-+ *
-+ * returns: >0 Number of bytes read
-+ * 0 Non-fatal error.
-+ * <0 Fatal error.
-+ */
-+static int roar_read(void *self, ref_buffer *rb)
-+{
-+ int result;
-+ im_roar_state *s = self;
-+
-+ rb->buf = malloc(BUFSIZE*2*s->channels);
-+ if(!rb->buf)
-+ return -1;
-+
-+ result = read(s->fd, rb->buf, BUFSIZE * 2 * s->channels);
-+
-+ rb->len = result;
-+ rb->aux_data = s->rate * s->channels * 2;
-+
-+ if(s->newtrack)
-+ {
-+ rb->critical = 1;
-+ s->newtrack = 0;
-+ }
-+
-+ if(result == -1 && (errno == EINTR || errno == ERESTART))
-+ {
-+ return 0; /* Non-fatal error */
-+ }
-+ else if(result <= 0)
-+ {
-+ if(result == 0)
-+ LOG_INFO0("Reached EOF, no more data available");
-+ else
-+ LOG_ERROR1("Error reading from sound server: %s", strerror(errno));
-+ free(rb->buf);
-+ return -1;
-+ }
-+
-+ return rb->len;
-+}
-+
-+input_module_t *roar_open_module(module_param_t *params)
-+{
-+ input_module_t *mod = calloc(1, sizeof(input_module_t));
-+ im_roar_state *s;
-+ module_param_t *current;
-+ char * server = NULL;
-+ int codec = ROAR_CODEC_DEFAULT;
-+ int bits = 16;
-+ int dir = ROAR_DIR_MONITOR;
-+ int use_metadata = 1; /* Default to on */
-+
-+ mod->getdata = roar_read;
-+ mod->handle_event = event_handler;
-+ mod->metadata_update = metadata_update;
-+
-+ mod->internal = calloc(1, sizeof(im_roar_state));
-+ s = mod->internal;
-+
-+ s->fd = -1; /* Set it to something invalid, for now */
-+ s->rate = 44100; /* Defaults */
-+ s->channels = 2;
-+
-+ thread_mutex_create(&s->metadatalock);
-+
-+ current = params;
-+
-+ while(current)
-+ {
-+ if(!strcmp(current->name, "rate"))
-+ s->rate = atoi(current->value);
-+ else if(!strcmp(current->name, "channels"))
-+ s->channels = atoi(current->value);
-+ else if(!strcmp(current->name, "codec"))
-+ codec = roar_str2codec(current->value);
-+ else if(!strcmp(current->name, "device"))
-+ server = current->value;
-+ else if(!strcmp(current->name, "metadata"))
-+ use_metadata = atoi(current->value);
-+ else if(!strcmp(current->name, "metadatafilename"))
-+ ices_config->metadata_filename = current->value;
-+ else
-+ LOG_WARN1("Unknown parameter %s for roar module", current->name);
-+
-+ current = current->next;
-+ }
-+
-+ mod->type = ICES_INPUT_PCM;
-+
-+ switch (codec) {
-+ case ROAR_CODEC_PCM_LE:
-+ mod->subtype = INPUT_PCM_LE_16;
-+ break;
-+ case ROAR_CODEC_PCM_BE:
-+ mod->subtype = INPUT_PCM_BE_16;
-+ break;
-+ case ROAR_CODEC_OGG_GENERAL:
-+ LOG_WARN0("Codec may not work, specify ogg_vorbis for Vorbis streaming");
-+ case ROAR_CODEC_OGG_VORBIS:
-+ mod->type = ICES_INPUT_VORBIS;
-+ // we do not set mod->subtype here, strange design ices2 has...
-+ break;
-+ case -1:
-+ LOG_ERROR0("Unknown Codec");
-+ return NULL;
-+ default:
-+ LOG_ERROR1("Unsupported Codec: %s", roar_codec2str(codec));
-+ return NULL;
-+ }
-+
-+
-+ /* First up, lets open the audio device */
-+ if ( roar_simple_connect(&s->con, server, "ices2") == -1 ) {
-+ LOG_ERROR2("Failed to open sound server %s: %s",
-+ server, strerror(errno));
-+ goto fail;
-+ }
-+
-+ /* Now, set the required parameters on that device */
-+ if ( (s->fd = roar_simple_new_stream_obj(&s->con, &s->stream, s->rate, s->channels, bits, codec, dir)) == -1 ) {
-+ LOG_ERROR2("Failed to create a new stream on sound server %s: %s",
-+ server, strerror(errno));
-+ goto fail;
-+ }
-+
-+ /* We're done, and we didn't fail! */
-+ LOG_INFO3("Opened sound server at %s at %d channel(s), %d Hz",
-+ server, s->channels, s->rate);
-+
-+ if(use_metadata)
-+ {
-+ LOG_INFO0("Starting metadata update thread");
-+ if(ices_config->metadata_filename)
-+ thread_create("im_roar-metadata", metadata_thread_signal, mod, 1);
-+ else
-+ thread_create("im_roar-metadata", metadata_thread_stdin, mod, 1);
-+ }
-+
-+ return mod;
-+
-+fail:
-+ close_module(mod); /* safe, this checks for valid contents */
-+ return NULL;
-+}
-+
-+
---- /dev/null
-+++ b/src/im_roar.h
-@@ -0,0 +1,36 @@
-+/* im_oss.h
-+ * - Raw PCM/Ogg Vorbis input from RoarAudio
-+ *
-+ * Copyright (c) 2001 Michael Smith <msmith at labyrinth.net.au>
-+ * Copyright (c) 2009 Philipp Schafft <lion at lion.leolix.org>
-+ *
-+ * This program is distributed under the terms of the GNU General
-+ * Public License, version 2. You may use, modify, and redistribute
-+ * it under the terms of this license. A copy should be included
-+ * with this source.
-+ */
-+
-+#ifndef __IM_ROAR_H__
-+#define __IM_ROAR_H__
-+
-+#include <thread/thread.h>
-+#include <roaraudio.h>
-+#include "inputmodule.h"
-+
-+typedef struct
-+{
-+ int rate;
-+ int channels;
-+
-+ struct roar_connection con;
-+ struct roar_stream stream;
-+
-+ int fd;
-+ char **metadata;
-+ int newtrack;
-+ mutex_t metadatalock;
-+} im_roar_state;
-+
-+input_module_t *roar_open_module(module_param_t *params);
-+
-+#endif /* __IM_ROAR_H__ */
---- a/src/input.c
-+++ b/src/input.c
-@@ -19,7 +19,9 @@
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
--#ifdef HAVE_STDINT_H
-+#ifdef HAVE_INTTYPES_H
-+#include <inttypes.h>
-+#elif defined(HAVE_STDINT_H)
- # include <stdint.h>
- #endif
- #include <ogg/ogg.h>
-@@ -36,6 +38,10 @@
- #include "im_playlist.h"
- #include "im_stdinpcm.h"
-
-+#ifdef HAVE_ROARAUDIO
-+#include "im_roar.h"
-+#endif
-+
- #ifdef HAVE_OSS
- #include "im_oss.h"
- #endif
-@@ -77,6 +83,9 @@
- static module modules[] = {
- { "playlist", playlist_open_module},
- { "stdinpcm", stdin_open_module},
-+#ifdef HAVE_ROARAUDIO
-+ { "roar", roar_open_module},
-+#endif
- #ifdef HAVE_OSS
- { "oss", oss_open_module},
- #endif
-@@ -280,6 +289,7 @@
- int valid_stream = 1;
- int inc_count;
- int not_waiting_for_critical;
-+ int foundmodule = 0;
-
- thread_cond_create(&ices_config->queue_cond);
- thread_cond_create(&ices_config->event_pending_cond);
-@@ -292,6 +302,7 @@
- {
- if(!strcmp(ices_config->playlist_module, modules[current_module].name))
- {
-+ foundmodule = 1;
- inmod = modules[current_module].open(ices_config->module_params);
- break;
- }
-@@ -300,8 +311,12 @@
-
- if(!inmod)
- {
-- LOG_ERROR1("Couldn't initialise input module \"%s\"",
-- ices_config->playlist_module);
-+ if(foundmodule)
-+ LOG_ERROR1("Couldn't initialise input module \"%s\"",
-+ ices_config->playlist_module);
-+ else
-+ LOG_ERROR1("No input module named \"%s\" could be found",
-+ ices_config->playlist_module);
- return;
- }
-
---- a/src/log/log.c
-+++ b/src/log/log.c
-@@ -46,6 +46,14 @@
- static mutex_t _logger_mutex;
- static int _initialized = 0;
-
-+typedef struct _log_entry_t
-+{
-+ char *line;
-+ unsigned int len;
-+ struct _log_entry_t *next;
-+} log_entry_t;
-+
-+
- typedef struct log_tag
- {
- int in_use;
-@@ -54,18 +62,25 @@
-
- char *filename;
- FILE *logfile;
-- unsigned size;
-- unsigned trigger_level;
-+ off_t size;
-+ off_t trigger_level;
-+ int archive_timestamp;
-+
-+ unsigned long total;
-+ unsigned int entries;
-+ unsigned int keep_entries;
-+ log_entry_t *log_head;
-+ log_entry_t **log_tail;
-
- char *buffer;
- } log_t;
-
- static log_t loglist[LOG_MAXLOGS];
-
--static int _get_log_id();
-+static int _get_log_id(void);
- static void _release_log_id(int log_id);
--static void _lock_logger();
--static void _unlock_logger();
-+static void _lock_logger(void);
-+static void _unlock_logger(void);
-
-
- static int _log_open (int id)
-@@ -83,11 +98,25 @@
-
- if (loglist [id] . logfile)
- {
-- char new_name [255];
-+ char new_name [4096];
- fclose (loglist [id] . logfile);
- loglist [id] . logfile = NULL;
- /* simple rename, but could use time providing locking were used */
-- snprintf (new_name, sizeof(new_name), "%s.old", loglist [id] . filename);
-+ if (loglist[id].archive_timestamp)
-+ {
-+ char timestamp [128];
-+ time_t now = time(NULL);
-+
-+ strftime (timestamp, sizeof (timestamp), "%Y%m%d_%H%M%S", localtime (&now));
-+ snprintf (new_name, sizeof(new_name), "%s.%s", loglist[id].filename, timestamp);
-+ }
-+ else {
-+ snprintf (new_name, sizeof(new_name), "%s.old", loglist [id] . filename);
-+ }
-+#ifdef _WIN32
-+ if (stat (new_name, &st) == 0)
-+ remove (new_name);
-+#endif
- rename (loglist [id] . filename, new_name);
- }
- loglist [id] . logfile = fopen (loglist [id] . filename, "a");
-@@ -105,7 +134,7 @@
- return 1;
- }
-
--void log_initialize()
-+void log_initialize(void)
- {
- int i;
-
-@@ -115,10 +144,15 @@
- loglist[i].in_use = 0;
- loglist[i].level = 2;
- loglist[i].size = 0;
-- loglist[i].trigger_level = 0;
-+ loglist[i].trigger_level = 1000000000;
- loglist[i].filename = NULL;
- loglist[i].logfile = NULL;
- loglist[i].buffer = NULL;
-+ loglist[i].total = 0;
-+ loglist[i].entries = 0;
-+ loglist[i].keep_entries = 0;
-+ loglist[i].log_head = NULL;
-+ loglist[i].log_tail = &loglist[i].log_head;
- }
-
- /* initialize mutexes */
-@@ -168,6 +202,9 @@
- loglist [id] . filename = strdup (filename);
- if (stat (loglist [id] . filename, &st) == 0)
- loglist [id] . size = st.st_size;
-+ loglist [id] . entries = 0;
-+ loglist [id] . log_head = NULL;
-+ loglist [id] . log_tail = &loglist [id] . log_head;
- }
-
- return id;
-@@ -188,7 +225,8 @@
- {
- if (id < 0 || id >= LOG_MAXLOGS)
- return LOG_EINSANE;
-- if (!strcmp(filename, "") || loglist [id] . in_use == 0)
-+ /* NULL filename is ok, empty filename is not. */
-+ if ((filename && !strcmp(filename, "")) || loglist [id] . in_use == 0)
- return LOG_EINSANE;
- _lock_logger();
- if (loglist [id] . filename)
-@@ -201,6 +239,16 @@
- return id;
- }
-
-+int log_set_archive_timestamp(int id, int value)
-+{
-+ if (id < 0 || id >= LOG_MAXLOGS)
-+ return LOG_EINSANE;
-+ _lock_logger();
-+ loglist[id].archive_timestamp = value;
-+ _unlock_logger();
-+ return id;
-+}
-+
-
- int log_open_with_buffer(const char *filename, int size)
- {
-@@ -209,6 +257,26 @@
- }
-
-
-+void log_set_lines_kept (int log_id, unsigned int count)
-+{
-+ if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
-+ if (loglist[log_id].in_use == 0) return;
-+
-+ _lock_logger ();
-+ loglist[log_id].keep_entries = count;
-+ while (loglist[log_id].entries > count)
-+ {
-+ log_entry_t *to_go = loglist [log_id].log_head;
-+ loglist [log_id].log_head = to_go->next;
-+ loglist [log_id].total -= to_go->len;
-+ free (to_go->line);
-+ free (to_go);
-+ loglist [log_id].entries--;
-+ }
-+ _unlock_logger ();
-+}
-+
-+
- void log_set_level(int log_id, unsigned level)
- {
- if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
-@@ -265,10 +333,19 @@
- fclose (loglist [log_id] . logfile);
- loglist [log_id] . logfile = NULL;
- }
-+ while (loglist[log_id].entries)
-+ {
-+ log_entry_t *to_go = loglist [log_id].log_head;
-+ loglist [log_id].log_head = to_go->next;
-+ loglist [log_id].total -= to_go->len;
-+ free (to_go->line);
-+ free (to_go);
-+ loglist [log_id].entries--;
-+ }
- _unlock_logger();
- }
-
--void log_shutdown()
-+void log_shutdown(void)
- {
- /* destroy mutexes */
- #ifndef _WIN32
-@@ -280,18 +357,80 @@
- _initialized = 0;
- }
-
-+
-+static int create_log_entry (int log_id, const char *pre, const char *line)
-+{
-+ log_entry_t *entry;
-+
-+ if (loglist[log_id].keep_entries == 0)
-+ return fprintf (loglist[log_id].logfile, "%s%s\n", pre, line);
-+
-+ entry = calloc (1, sizeof (log_entry_t));
-+ entry->len = strlen (pre) + strlen (line) + 2;
-+ entry->line = malloc (entry->len);
-+ snprintf (entry->line, entry->len, "%s%s\n", pre, line);
-+ loglist [log_id].total += entry->len;
-+ fprintf (loglist[log_id].logfile, "%s", entry->line);
-+
-+ *loglist [log_id].log_tail = entry;
-+ loglist [log_id].log_tail = &entry->next;
-+
-+ if (loglist [log_id].entries >= loglist [log_id].keep_entries)
-+ {
-+ log_entry_t *to_go = loglist [log_id].log_head;
-+ loglist [log_id].log_head = to_go->next;
-+ loglist [log_id].total -= to_go->len;
-+ free (to_go->line);
-+ free (to_go);
-+ }
-+ else
-+ loglist [log_id].entries++;
-+ return entry->len;
-+}
-+
-+
-+void log_contents (int log_id, char **_contents, unsigned int *_len)
-+{
-+ int remain;
-+ log_entry_t *entry;
-+ char *ptr;
-+
-+ if (log_id < 0) return;
-+ if (log_id >= LOG_MAXLOGS) return; /* Bad log number */
-+
-+ _lock_logger ();
-+ remain = loglist [log_id].total + 1;
-+ *_contents = malloc (remain);
-+ **_contents= '\0';
-+ *_len = loglist [log_id].total;
-+
-+ entry = loglist [log_id].log_head;
-+ ptr = *_contents;
-+ while (entry)
-+ {
-+ int len = snprintf (ptr, remain, "%s", entry->line);
-+ if (len > 0)
-+ {
-+ ptr += len;
-+ remain -= len;
-+ }
-+ entry = entry->next;
-+ }
-+ _unlock_logger ();
-+}
-+
-+
- void log_write(int log_id, unsigned priority, const char *cat, const char *func,
- const char *fmt, ...)
- {
- static char *prior[] = { "EROR", "WARN", "INFO", "DBUG" };
-- char tyme[128];
-+ int datelen;
-+ time_t now;
- char pre[256];
- char line[LOG_MAXLINELEN];
-- time_t now;
- va_list ap;
-
-- if (log_id < 0) return;
-- if (log_id > LOG_MAXLOGS) return; /* Bad log number */
-+ if (log_id < 0 || log_id >= LOG_MAXLOGS) return; /* Bad log number */
- if (loglist[log_id].level < priority) return;
- if (priority > sizeof(prior)/sizeof(prior[0])) return; /* Bad priority */
-
-@@ -301,13 +440,13 @@
- now = time(NULL);
-
- _lock_logger();
-- strftime(tyme, sizeof (tyme), "[%Y-%m-%d %H:%M:%S]", localtime(&now));
-+ datelen = strftime (pre, sizeof (pre), "[%Y-%m-%d %H:%M:%S]", localtime(&now));
-
-- snprintf(pre, sizeof (pre), "%s %s%s", prior[priority-1], cat, func);
-+ snprintf (pre+datelen, sizeof (pre)-datelen, " %s %s%s ", prior [priority-1], cat, func);
-
- if (_log_open (log_id))
- {
-- int len = fprintf (loglist[log_id].logfile, "%s %s %s\n", tyme, pre, line);
-+ int len = create_log_entry (log_id, pre, line);
- if (len > 0)
- loglist[log_id].size += len;
- }
-@@ -318,18 +457,21 @@
-
- void log_write_direct(int log_id, const char *fmt, ...)
- {
-- char line[LOG_MAXLINELEN];
- va_list ap;
-+ time_t now;
-+ char line[LOG_MAXLINELEN];
-
-- if (log_id < 0) return;
-+ if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
-
- va_start(ap, fmt);
-
-+ now = time(NULL);
-+
- _lock_logger();
- vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
- if (_log_open (log_id))
- {
-- int len = fprintf(loglist[log_id].logfile, "%s\n", line);
-+ int len = create_log_entry (log_id, "", line);
- if (len > 0)
- loglist[log_id].size += len;
- }
-@@ -340,7 +482,7 @@
- fflush(loglist[log_id].logfile);
- }
-
--static int _get_log_id()
-+static int _get_log_id(void)
- {
- int i;
- int id = -1;
-@@ -372,7 +514,7 @@
- _unlock_logger();
- }
-
--static void _lock_logger()
-+static void _lock_logger(void)
- {
- #ifndef _WIN32
- pthread_mutex_lock(&_logger_mutex);
-@@ -381,7 +523,7 @@
- #endif
- }
-
--static void _unlock_logger()
-+static void _unlock_logger(void)
- {
- #ifndef _WIN32
- pthread_mutex_unlock(&_logger_mutex);
---- a/src/log/log.h
-+++ b/src/log/log.h
-@@ -22,20 +22,23 @@
- #define IO_BUFFER_TYPE _IOLBF
- #endif
-
--void log_initialize();
-+void log_initialize(void);
- int log_open_file(FILE *file);
- int log_open(const char *filename);
- int log_open_with_buffer(const char *filename, int size);
- void log_set_level(int log_id, unsigned level);
- void log_set_trigger(int id, unsigned trigger);
- int log_set_filename(int id, const char *filename);
-+void log_set_lines_kept (int log_id, unsigned int count);
-+void log_contents (int log_id, char **_contents, unsigned int *_len);
-+int log_set_archive_timestamp(int id, int value);
- void log_flush(int log_id);
- void log_reopen(int log_id);
- void log_close(int log_id);
--void log_shutdown();
-+void log_shutdown(void);
-
- void log_write(int log_id, unsigned priority, const char *cat, const char *func,
- const char *fmt, ...);
--void log_write_direct(int log_id, const char *fmt, ...);
-+void log_write_direct(int log_id, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-
- #endif /* __LOG_H__ */
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -8,7 +8,7 @@
- AM_CPPFLAGS = @XIPH_CPPFLAGS@
- AM_CFLAGS = @XIPH_CFLAGS@
-
--EXTRA_ices_SOURCES = im_oss.c im_sun.c im_alsa.c
-+EXTRA_ices_SOURCES = im_oss.c im_sun.c im_alsa.c im_roar.c
-
- if HAVE_OSS
- oss = im_oss.c
-@@ -22,14 +22,19 @@
- alsa = im_alsa.c
- endif
-
--dist_noinst_HEADERS = cfgparse.h input.h inputmodule.h im_playlist.h signals.h stream.h reencode.h encode.h playlist_basic.h logging.h im_stdinpcm.h event.h stream_shared.h metadata.h audio.h resample.h im_sun.h im_oss.h im_alsa.h
-+if HAVE_ROARAUDIO
-+roar = im_roar.c
-+endif
-+
-+dist_noinst_HEADERS = cfgparse.h input.h inputmodule.h im_playlist.h signals.h stream.h reencode.h encode.h playlist_basic.h logging.h im_stdinpcm.h event.h stream_shared.h metadata.h audio.h resample.h im_sun.h im_oss.h im_alsa.h im_roar.h
-
--ices_SOURCES = input.c cfgparse.c stream.c ices.c signals.c im_playlist.c reencode.c encode.c playlist_basic.c im_stdinpcm.c stream_shared.c metadata.c playlist_script.c audio.c resample.c $(oss) $(sun) $(alsa)
-+ices_SOURCES = input.c cfgparse.c stream.c ices.c signals.c im_playlist.c reencode.c encode.c playlist_basic.c im_stdinpcm.c stream_shared.c metadata.c playlist_script.c audio.c resample.c $(oss) $(sun) $(alsa) $(roar)
-
- ices_LDADD = log/libicelog.la \
- timing/libicetiming.la \
- thread/libicethread.la \
- avl/libiceavl.la \
-+ @ROARAUDIO_LIBS@ \
- @ALSA_LIBS@ @XIPH_LIBS@
-
- debug:
---- a/src/metadata.c
-+++ b/src/metadata.c
-@@ -20,6 +20,9 @@
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
-+#ifdef HAVE_SYS_SELECT_H
-+#include <sys/select.h>
-+#endif
-
- #include "cfgparse.h"
- #include "inputmodule.h"
---- a/src/stream.c
-+++ b/src/stream.c
-@@ -291,13 +291,16 @@
- input_flush_queue(stream->queue, 1);
- thread_mutex_unlock(&ices_config->flush_lock);
-
-+ shout_close(sdsc->shout);
-+
-+ if (i >= stream->reconnect_attempts)
-+ break;
- while((i < stream->reconnect_attempts ||
- stream->reconnect_attempts==-1) &&
- !ices_config->shutdown)
- {
-- i++;
- LOG_WARN0("Trying reconnect after server socket error");
-- shout_close(sdsc->shout);
-+ i++;
- if((shouterr = shout_open(sdsc->shout)) == SHOUTERR_SUCCESS)
- {
- LOG_INFO3("Connected to server: %s:%d%s",
-@@ -312,6 +315,7 @@
- thread_mutex_lock(&ices_config->flush_lock);
- stream->wait_for_critical = 1;
- input_flush_queue(stream->queue, 0);
-+ stream->skip = 0;
- thread_mutex_unlock(&ices_config->flush_lock);
- break;
- }
-@@ -331,7 +335,6 @@
- thread_sleep (stream->reconnect_delay*1000000);
- }
- }
-- stream->skip = 0;
- }
- stream->buffer_failures++;
- }
---- a/src/thread/thread.c
-+++ b/src/thread/thread.c
-@@ -36,7 +36,6 @@
- #else
- #include <windows.h>
- #include <winbase.h>
--#include <implement.h>
- #endif
-
- #include <signal.h>
-@@ -196,6 +195,7 @@
- avl_tree_free(_mutextree, _free_mutex);
- #endif
- avl_tree_free(_threadtree, _free_thread);
-+ _threadtree = NULL;
- }
-
- #ifdef THREAD_DEBUG
-@@ -223,6 +223,7 @@
- sigdelset(&ss, SIGKILL);
- sigdelset(&ss, SIGSTOP);
- sigdelset(&ss, SIGSEGV);
-+ sigdelset(&ss, SIGCHLD);
- sigdelset(&ss, SIGBUS);
- if (pthread_sigmask(SIG_BLOCK, &ss, NULL) != 0) {
- #ifdef THREAD_DEBUG
-@@ -292,6 +293,7 @@
- start->arg = arg;
- start->thread = thread;
-
-+ pthread_attr_setstacksize (&attr, 512*1024);
- pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED);
- if (detached)
- {
-@@ -594,7 +596,7 @@
- avl_delete(_threadtree, th, _free_thread);
- _mutex_unlock(&_threadtree_mutex);
- }
--
-+
- pthread_exit ((void*)val);
- }
-
-@@ -811,3 +813,29 @@
- }
-
-
-+#ifdef HAVE_PTHREAD_SPIN_LOCK
-+void thread_spin_create (spin_t *spin)
-+{
-+ int x = pthread_spin_init (&spin->lock, PTHREAD_PROCESS_PRIVATE);
-+ if (x)
-+ abort();
-+}
-+
-+void thread_spin_destroy (spin_t *spin)
-+{
-+ pthread_spin_destroy (&spin->lock);
-+}
-+
-+void thread_spin_lock (spin_t *spin)
-+{
-+ int x = pthread_spin_lock (&spin->lock);
-+ if (x != 0)
-+ abort();
-+}
-+
-+void thread_spin_unlock (spin_t *spin)
-+{
-+ pthread_spin_unlock (&spin->lock);
-+}
-+#endif
-+
---- a/src/thread/thread.h
-+++ b/src/thread/thread.h
-@@ -89,6 +89,24 @@
- pthread_rwlock_t sys_rwlock;
- } rwlock_t;
-
-+#ifdef HAVE_PTHREAD_SPIN_LOCK
-+typedef struct
-+{
-+ pthread_spinlock_t lock;
-+} spin_t;
-+
-+void thread_spin_create (spin_t *spin);
-+void thread_spin_destroy (spin_t *spin);
-+void thread_spin_lock (spin_t *spin);
-+void thread_spin_unlock (spin_t *spin);
-+#else
-+typedef mutex_t spin_t;
-+#define thread_spin_create(x) thread_mutex_create(x)
-+#define thread_spin_destroy(x) thread_mutex_destroy(x)
-+#define thread_spin_lock(x) thread_mutex_lock(x)
-+#define thread_spin_unlock(x) thread_mutex_unlock(x)
-+#endif
-+
- #define thread_create(n,x,y,z) thread_create_c(n,x,y,z,__LINE__,__FILE__)
- #define thread_mutex_create(x) thread_mutex_create_c(x,__LINE__,__FILE__)
- #define thread_mutex_lock(x) thread_mutex_lock_c(x,__LINE__,__FILE__)
---- a/src/timing/timing.c
-+++ b/src/timing/timing.c
-@@ -11,15 +11,22 @@
-
- #include <stdlib.h>
- #include <sys/types.h>
--#ifdef HAVE_STDINT_H
--# include <stdint.h>
--#endif
-
- #ifdef _WIN32
- #include <windows.h>
- #include <mmsystem.h>
- #else
--#include <sys/time.h>
-+#ifdef TIME_WITH_SYS_TIME
-+# include <sys/time.h>
-+# include <time.h>
-+#else
-+# ifdef HAVE_SYS_TIME_H
-+# include <sys/time.h>
-+# else
-+# include <time.h>
-+# endif
-+#endif
-+
- #include <unistd.h>
- #endif
-
-@@ -27,7 +34,7 @@
- #include <sys/select.h>
- #endif
-
--#ifdef __MINGW32__
-+#ifdef HAVE_SYS_TIMEB_H
- #include <sys/timeb.h>
- #endif
-
-@@ -40,24 +47,23 @@
- */
- uint64_t timing_get_time(void)
- {
--#ifdef _WIN32
--#ifdef __MINGW32__
-- struct timeb t;
--
-- ftime(&t);
-- return t.time * 1000 + t.millitm;
--#else
-- return timeGetTime();
--#endif
--#else
-+#ifdef HAVE_GETTIMEOFDAY
- struct timeval mtv;
-
- gettimeofday(&mtv, NULL);
-
- return (uint64_t)(mtv.tv_sec) * 1000 + (uint64_t)(mtv.tv_usec) / 1000;
-+#elif HAVE_FTIME
-+ struct timeb t;
-+
-+ ftime(&t);
-+ return t.time * 1000 + t.millitm;
-+#else
-+#error need time query handler
- #endif
- }
-
-+
- void timing_sleep(uint64_t sleeptime)
- {
- struct timeval sleeper;
---- a/src/timing/timing.h
-+++ b/src/timing/timing.h
-@@ -9,11 +9,13 @@
- #define __TIMING_H__
-
- #include <sys/types.h>
--#ifdef HAVE_STDINT_H
-+#ifdef HAVE_INTTYPES_H
-+#include <inttypes.h>
-+#elif defined(HAVE_STDINT_H)
- #include <stdint.h>
- #endif
-
--#ifdef _WIN32
-+#if defined(_WIN32) && !defined(int64_t)
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
- #endif
diff --git a/debian/patches/0001_sync_upstream_VCS.patch b/debian/patches/0001_sync_upstream_VCS.patch
new file mode 100644
index 0000000..4dae910
--- /dev/null
+++ b/debian/patches/0001_sync_upstream_VCS.patch
@@ -0,0 +1,1678 @@
+Description: Sync to upstream Subversion repository
+Author: The IceS Development Team <team at icecast.org>
+Origin: http://svn.xiph.org/icecast/trunk/ices
+Forwarded: yes
+Applied-Upstream: r18199
+Last-Update: 2012-03-27
+
+--- /dev/null
++++ b/conf/ices-roar.xml
+@@ -0,0 +1,121 @@
++<?xml version="1.0"?>
++<ices>
++
++ <!-- run in background -->
++ <background>0</background>
++ <!-- where logs go. -->
++ <logpath>/var/log/ices</logpath>
++ <logfile>ices.log</logfile>
++ <!-- size in kilobytes -->
++ <logsize>2048</logsize>
++ <!-- 1=error, 2=warn, 3=infoa ,4=debug -->
++ <loglevel>4</loglevel>
++ <!-- logfile is ignored if this is set to 1 -->
++ <consolelog>0</consolelog>
++
++ <!-- optional filename to write process id to -->
++ <!-- <pidfile>/home/ices/ices.pid</pidfile> -->
++
++ <stream>
++ <!-- metadata used for stream listing -->
++ <metadata>
++ <name>Example stream name</name>
++ <genre>Example genre</genre>
++ <description>A short description of your stream</description>
++ <url>http://mysite.org</url>
++ </metadata>
++
++ <!-- Input module.
++
++ This example uses the 'oss' module. It takes input from the
++ OSS audio device (e.g. line-in), and processes it for live
++ encoding. -->
++ <input>
++ <module>roar</module>
++ <!-- All of the following settings are optional.
++ You should not set them if not needed. -->
++
++ <!-- Sample rate and number or channels, defaults are 44.1kHz and stereo -->
++ <param name="rate">44100</param>
++ <param name="channels">2</param>
++
++ <!-- The codec to read audio from the server in. This is *NOT*
++ the codec the audio is streamed to the server.
++ Default should be raw PCM ("default").
++ You may also use "ogg_vorbis".
++ -->
++ <param name="codec">default</param>
++
++ <!-- The stream direction:
++ Use "monitor" for sending a copy of your output to the server or
++ "record" to record from sound card.
++ Defaults to "monitor".
++ -->
++ <param name="dir">monitor</param>
++
++ <!-- This is the address of the server to connect to.
++ This can be a /path/to/unixsocket, a host or node name.
++ You sould not set this value for local roard unless
++ needed. Setting this to 'localhost' is normaly a bad idea.
++ -->
++ <param name="device">somehost</param>
++
++ <!-- Read metadata (from stdin by default, or -->
++ <!-- filename defined below (if the latter, only on SIGUSR1) -->
++ <param name="metadata">file</param>
++ <param name="metadatafilename">test</param>
++ </input>
++
++ <!-- Stream instance.
++
++ You may have one or more instances here. This allows you to
++ send the same input data to one or more servers (or to different
++ mountpoints on the same server). Each of them can have different
++ parameters. This is primarily useful for a) relaying to multiple
++ independent servers, and b) encoding/reencoding to multiple
++ bitrates.
++
++ If one instance fails (for example, the associated server goes
++ down, etc), the others will continue to function correctly.
++ This example defines a single instance doing live encoding at
++ low bitrate. -->
++
++ <instance>
++ <!-- Server details.
++
++ You define hostname and port for the server here, along
++ with the source password and mountpoint. -->
++
++ <hostname>localhost</hostname>
++ <port>8000</port>
++ <password>hackme</password>
++ <mount>/example1.ogg</mount>
++ <yp>1</yp> <!-- allow stream to be advertised on YP, default 0 -->
++
++ <!-- Live encoding/reencoding:
++
++ channels and samplerate currently MUST match the channels
++ and samplerate given in the parameters to the oss input
++ module above or the remsaple/downmix section below. -->
++
++ <encode>
++ <quality>0</quality>
++ <samplerate>22050</samplerate>
++ <channels>1</channels>
++ </encode>
++
++ <!-- stereo->mono downmixing, enabled by setting this to 1 -->
++ <downmix>1</downmix>
++
++ <!-- resampling.
++
++ Set to the frequency (in Hz) you wish to resample to, -->
++
++ <resample>
++ <in-rate>44100</in-rate>
++ <out-rate>22050</out-rate>
++ </resample>
++ </instance>
++
++ </stream>
++</ices>
+--- a/configure.in
++++ b/configure.in
+@@ -14,12 +14,6 @@
+
+ dnl BSD headers break when _XOPEN_SOURCE is defined but without it seems
+ dnl to be fine
+-case "$host" in
+- *bsd*|*irix*)
+- ;;
+- *) AC_DEFINE(_XOPEN_SOURCE, 600, [Define if you have POSIX and XPG specifications])
+- ;;
+-esac
+ if test -n "$GCC"; then
+ AC_DEFINE(_GNU_SOURCE, ,[Define if you have POSIX and GNU specifications])
+ XIPH_VAR_APPEND([XIPH_CPPFLAGS], [-ffast-math -fsigned-char])
+@@ -52,7 +46,7 @@
+
+ dnl Checks for header files.
+ AC_HEADER_STDC
+-AC_CHECK_HEADERS([stropts.h])
++AC_CHECK_HEADERS([stropts.h sys/timeb.h sys/select.h])
+
+ dnl Check for OSS
+
+@@ -91,6 +85,16 @@
+ AC_DEFINE(HAVE_ALSA, ,[Define to enable ALSA input module])
+ fi
+
++dnl Check for RoarAudio
++
++AC_CHECK_HEADER(roaraudio.h, have_roaraudio=yes, have_roaraudio=no)
++AM_CONDITIONAL(HAVE_ROARAUDIO,test "$have_roaraudio" = yes)
++
++if test "$have_roaraudio" = yes; then
++ ROARAUDIO_LIBS="-lroar"
++ AC_DEFINE(HAVE_ROARAUDIO, ,[Define to enable RoarAudio input module])
++fi
++
+ dnl Checks for typedefs, structures, and compiler characteristics.
+ AC_C_CONST
+
+@@ -99,6 +103,8 @@
+
+ dnl Checks for library functions.
+
++AC_CHECK_FUNCS([gettimeofday ftime])
++
+ XIPH_PATH_XML
+ XIPH_VAR_APPEND([XIPH_CFLAGS], [$XML_CFLAGS])
+ XIPH_VAR_PREPEND([XIPH_LIBS], [$XML_LIBS])
+@@ -120,6 +126,7 @@
+ dnl Make substitutions
+
+ AC_SUBST(ALSA_LIBS)
++AC_SUBST(ROARAUDIO_LIBS)
+ AC_SUBST(XML_LIBS)
+ AC_SUBST(XML_CFLAGS)
+ AC_SUBST(LIBTOOL_DEPS)
+--- /dev/null
++++ b/contrib/run_ices
+@@ -0,0 +1,150 @@
++#!/bin/sh
++
++# script to help automate generation of config file and startup of ices2,
++# mostly useful for people trying to do things like run ices2 from cron.
++
++# contributed by Ciaran Anscomb <ciarana at rd.bbc.co.uk>
++# distributed under GPL, see LICENSE
++
++# You will probably want to leave this commented out - I need it tho...
++#LD_LIBRARY_PATH=/usr/local/ogg/lib
++#export LD_LIBRARY_PATH
++#PATH=/usr/local/ogg/bin:/usr/ucb:/usr/bin:/usr/etc
++#cd /usr/local/ogg/bin
++
++# Some moderately sensible defaults
++samplerate=44100
++channels=2
++bitrate=64000
++module=oss
++server=localhost
++port=8000
++password=hackme
++metadatafile=/var/tmp/metadata.$$
++
++start_wgets() {
++ while [ "x$1" != "x" ]; do
++ mount=$1; shift
++ outfile=$1; shift
++ wget -q http://$server:$port/$mount -O $outfile &
++ done
++}
++
++cleanup() {
++ rm -f $metadatafile
++}
++
++trap cleanup 2 15
++
++if [ "x$1" = "x" -o "x$1" = "x--help" -o "x$1" = "x-h" ]; then
++ cat << EOF
++run_ices, a script to start ices2 from the command line.
++Usage: $0 [OPTION] mountpoint [-o filename] ...
++Example: $0 -S localhost -P 8000 -p hackme -b 64000 path/low.ogg
++ -o low.ogg -b 128000 path/high.ogg -o high.ogg
++
++General configuration:
++ -sr n Set sample rate of audio device [$samplerate]
++ -c n Set number of channels [$channels]
++ -m module Use named ices module (oss,sun) [$module]
++ -S server Server to stream to [$server]
++ -P port Port to connect to [$port]
++ -p pass Server password
++ -A title Artist for encoding
++ -T title Title for encoding
++ -t n Finish encoding after n seconds [don't stop]
++
++Per-instance encoding configuration:
++ -b n Set bitrate [$bitrate]
++ -o filename Spawn a wget process to write this encoding to file
++
++When listing more than one mountpoint, you only need to override the
++parameters that need changing since the last one. Multiple encodings
++come at the expense of CPU. If you use -o, always specify it AFTER the
++mountpoint, and make sure you have the GNU wget application installed.
++
++EOF
++ exit 0
++fi
++
++while [ "x$1" != "x" ]; do
++ opt=$1; shift
++ case $opt in
++ -sr) samplerate=$1; shift; ;;
++ -c) channels=$1; shift; ;;
++ -m) module=$1; shift; ;;
++ -S) server=$1; shift; ;;
++ -P) port=$1; shift; ;;
++ -p) password=$1; shift; ;;
++ -T) title=$1; shift; ;;
++ -A) artist=$1; shift; ;;
++ -o) outdata="$mount $1 $outdata"; shift; ;;
++ -t) time=$1; shift; ;;
++ -b) bitrate=$1; shift; ;;
++ *) mount=$opt;
++ if [ "x$init" = "x" ]; then
++ cat > live.xml << EOF
++<?xml version="1.0"?>
++<ices>
++ <background>0</background>
++ <logpath>/usr/local/ogg/log</logpath>
++ <logfile>ices.log</logfile>
++ <loglevel>1</loglevel>
++
++ <stream>
++ <metadata>
++ <name>Ogg stream</name>
++ <genre>misc</genre>
++ <description>No description</description>
++ </metadata>
++ <input>
++ <module>$module</module>
++ <param name="rate">$samplerate</param>
++ <param name="channels">$channels</param>
++ <param name="device">/dev/audio</param>
++ <param name="metadata">1</param>
++ <param name="metadatafilename">$metadatafile</param>
++ </input>
++EOF
++ init=1
++ fi
++ cat >> live.xml << EOF
++ <instance>
++ <hostname>$server</hostname>
++ <port>$port</port>
++ <password>$password</password>
++ <mount>/$mount</mount>
++ <encode>
++ <bitrate>$bitrate</bitrate>
++ <samplerate>$samplerate</samplerate>
++ <channels>$channels</channels>
++ </encode>
++ </instance>
++EOF
++ ;;
++ esac
++done
++
++cat >> live.xml << EOF
++ </stream>
++</ices>
++EOF
++
++cat > $metadatafile << EOF
++ARTIST=$artist
++TITLE=$title
++EOF
++ices live.xml &
++icespid=$!
++kill -USR1 $icespid
++if [ "x$outdata" != "x" ]; then
++ sleep 2
++ start_wgets $outdata
++fi
++if [ "x$time" != "x" ]; then
++ sleep $time
++ kill -INT $icespid
++else
++ wait $icespid
++fi
++cleanup
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -6,9 +6,9 @@
+
+ bin_PROGRAMS = ices
+ AM_CPPFLAGS = @XIPH_CPPFLAGS@
+-AM_CFLAGS = @XIPH_CFLAGS@
++AM_CFLAGS = @XIPH_CFLAGS@ -Wall
+
+-EXTRA_ices_SOURCES = im_oss.c im_sun.c im_alsa.c
++EXTRA_ices_SOURCES = im_oss.c im_sun.c im_alsa.c im_roar.c
+
+ if HAVE_OSS
+ oss = im_oss.c
+@@ -22,14 +22,19 @@
+ alsa = im_alsa.c
+ endif
+
+-dist_noinst_HEADERS = cfgparse.h input.h inputmodule.h im_playlist.h signals.h stream.h reencode.h encode.h playlist_basic.h logging.h im_stdinpcm.h event.h stream_shared.h metadata.h audio.h resample.h im_sun.h im_oss.h im_alsa.h
++if HAVE_ROARAUDIO
++roar = im_roar.c
++endif
++
++dist_noinst_HEADERS = cfgparse.h input.h inputmodule.h im_playlist.h signals.h stream.h reencode.h encode.h playlist_basic.h logging.h im_stdinpcm.h event.h stream_shared.h metadata.h audio.h resample.h im_sun.h im_oss.h im_alsa.h im_roar.h
+
+-ices_SOURCES = input.c cfgparse.c stream.c ices.c signals.c im_playlist.c reencode.c encode.c playlist_basic.c im_stdinpcm.c stream_shared.c metadata.c playlist_script.c audio.c resample.c $(oss) $(sun) $(alsa)
++ices_SOURCES = input.c cfgparse.c stream.c ices.c signals.c im_playlist.c reencode.c encode.c playlist_basic.c im_stdinpcm.c stream_shared.c metadata.c playlist_script.c audio.c resample.c $(oss) $(sun) $(alsa) $(roar)
+
+ ices_LDADD = log/libicelog.la \
+ timing/libicetiming.la \
+ thread/libicethread.la \
+ avl/libiceavl.la \
++ @ROARAUDIO_LIBS@ \
+ @ALSA_LIBS@ @XIPH_LIBS@
+
+ debug:
+--- a/src/im_playlist.c
++++ b/src/im_playlist.c
+@@ -167,12 +167,8 @@
+ if (ogg_page_bos (&og))
+ {
+ if (ogg_page_serialno (&og) == pl->current_serial)
+- {
+- LOG_WARN1 ("Skipping \"%s\" as the serial number is the same as previous", pl->filename);
+- pl->nexttrack = 1;
+- pl->errors++;
+- return 0;
+- }
++ LOG_WARN1 ("detected duplicate serial number reading \"%s\"", pl->filename);
++
+ pl->current_serial = ogg_page_serialno (&og);
+ }
+ if (input_calculate_ogg_sleep (&og) < 0)
+--- /dev/null
++++ b/src/im_roar.c
+@@ -0,0 +1,307 @@
++/* im_oss.c
++ * - Raw PCM/Ogg Vorbis input from RoarAudio
++ *
++ * Copyright (c) 2001 Michael Smith <msmith at labyrinth.net.au>
++ * Copyright (c) 2009-2012 Philipp Schafft <lion at lion.leolix.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#ifdef HAVE_CONFIG_H
++ #include <config.h>
++#endif
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <ogg/ogg.h>
++#include <fcntl.h>
++
++
++#include <thread/thread.h>
++#include "cfgparse.h"
++#include "stream.h"
++#include "metadata.h"
++#include "inputmodule.h"
++
++#include "im_roar.h"
++
++#ifdef ROAR_FT_SONAME_LIBROAR2
++#define _set_flags roar_stream_set_flags
++#else
++#define _set_flags roar_stream_set_flags2
++#endif
++
++#define MODULE "input-roar/"
++#include "logging.h"
++
++#define BUFSIZE 2048
++
++/* Some platforms (freebsd) don't define this, so just define it to something
++ * that should be treated the same
++ */
++#ifndef ERESTART
++#define ERESTART EINTR
++#endif
++
++static void close_module(input_module_t *mod)
++{
++ if(mod)
++ {
++ if(mod->internal)
++ {
++ im_roar_state *s = mod->internal;
++
++ if(s->vss)
++ roar_vs_close(s->vss, ROAR_VS_TRUE, NULL);
++
++
++ thread_mutex_destroy(&s->metadatalock);
++ free(s);
++ }
++ free(mod);
++ }
++}
++
++static int event_handler(input_module_t *mod, enum event_type ev, void *param)
++{
++ im_roar_state *s = mod->internal;
++
++ switch(ev)
++ {
++ case EVENT_SHUTDOWN:
++ close_module(mod);
++ break;
++ case EVENT_NEXTTRACK:
++ s->newtrack = 1;
++ break;
++ case EVENT_METADATAUPDATE:
++ thread_mutex_lock(&s->metadatalock);
++ if(s->metadata)
++ {
++ char **md = s->metadata;
++ while(*md)
++ free(*md++);
++ free(s->metadata);
++ }
++ s->metadata = (char **)param;
++ s->newtrack = 1;
++ thread_mutex_unlock(&s->metadatalock);
++ break;
++ default:
++ LOG_WARN1("Unhandled event %d", ev);
++ return -1;
++ }
++
++ return 0;
++}
++
++static void metadata_update(void *self, vorbis_comment *vc)
++{
++ im_roar_state *s = self;
++ char **md;
++
++ thread_mutex_lock(&s->metadatalock);
++
++ md = s->metadata;
++
++ if(md)
++ {
++ while(*md)
++ vorbis_comment_add(vc, *md++);
++ }
++
++ thread_mutex_unlock(&s->metadatalock);
++}
++
++/* Core streaming function for this module
++ * This is what actually produces the data which gets streamed.
++ *
++ * returns: >0 Number of bytes read
++ * 0 Non-fatal error.
++ * <0 Fatal error.
++ */
++static int roar_read(void *self, ref_buffer *rb)
++{
++ int result;
++ int err;
++ im_roar_state *s = self;
++
++ rb->buf = malloc(BUFSIZE*2*s->info.channels);
++ if(!rb->buf)
++ return -1;
++
++ result = roar_vs_read(s->vss, rb->buf, BUFSIZE * 2 * s->info.channels, &err);
++
++ rb->len = result;
++ rb->aux_data = s->info.rate * s->info.channels * 2;
++
++ if(s->newtrack)
++ {
++ rb->critical = 1;
++ s->newtrack = 0;
++ }
++
++ if(result == -1 && err == ROAR_ERROR_INTERRUPTED)
++ {
++ return 0; /* Non-fatal error */
++ }
++ else if(result <= 0)
++ {
++ if(result == 0)
++ LOG_INFO0("Reached EOF, no more data available");
++ else
++ LOG_ERROR1("Error reading from sound server: %s", roar_vs_strerr(err));
++ free(rb->buf);
++ return -1;
++ }
++
++ return rb->len;
++}
++
++input_module_t *roar_open_module(module_param_t *params)
++{
++ input_module_t *mod = calloc(1, sizeof(input_module_t));
++ im_roar_state *s;
++ module_param_t *current;
++ const char * server = NULL;
++ int dir = ROAR_DIR_MONITOR;
++ enum { MD_NONE = 0, MD_FILE = 1, MD_STREAM = 2 } use_metadata = MD_STREAM;
++ int err;
++
++ mod->getdata = roar_read;
++ mod->handle_event = event_handler;
++ mod->metadata_update = metadata_update;
++
++ mod->internal = calloc(1, sizeof(im_roar_state));
++ s = mod->internal;
++
++ if(roar_profile2info(&s->info, "default") == -1)
++ {
++ LOG_ERROR1("Failed to get default audio profile: %s",
++ roar_error2str(roar_error));
++ return NULL;
++ }
++ s->info.bits = 16;
++
++ s->vss = NULL;
++
++ thread_mutex_create(&s->metadatalock);
++
++ current = params;
++
++ while(current)
++ {
++ if(!strcmp(current->name, "rate"))
++ s->info.rate = roar_str2rate(current->value);
++ else if(!strcmp(current->name, "channels"))
++ s->info.channels = roar_str2channels(current->value);
++ else if(!strcmp(current->name, "codec"))
++ s->info.codec = roar_str2codec(current->value);
++ else if(!strcmp(current->name, "dir")) {
++ if ( !strcasecmp(current->value, "monitor") ) {
++ dir = ROAR_DIR_MONITOR;
++ } else if ( !strcasecmp(current->value, "record") ) {
++ dir = ROAR_DIR_RECORD;
++ } else {
++ LOG_WARN2("Unknown value %s for parameter %s for roar module", current->value, current->name);
++ }
++ } else if(!strcmp(current->name, "device") || !strcmp(current->name, "server"))
++ server = current->value;
++ else if(!strcmp(current->name, "metadata")) {
++ if ( !strcasecmp(current->value, "none") ) {
++ use_metadata = MD_NONE;
++ } else if ( !strcasecmp(current->value, "file") ) {
++ use_metadata = MD_FILE;
++ } else if ( !strcasecmp(current->value, "stream") ) {
++ use_metadata = MD_STREAM;
++ } else {
++ use_metadata = atoi(current->value);
++ }
++ } else if(!strcmp(current->name, "metadatafilename")) {
++ ices_config->metadata_filename = current->value;
++ use_metadata = MD_FILE;
++ } else
++ LOG_WARN1("Unknown parameter %s for roar module", current->name);
++
++ current = current->next;
++ }
++
++ mod->type = ICES_INPUT_PCM;
++
++ switch (s->info.codec) {
++ case ROAR_CODEC_PCM_LE:
++ mod->subtype = INPUT_PCM_LE_16;
++ break;
++ case ROAR_CODEC_PCM_BE:
++ mod->subtype = INPUT_PCM_BE_16;
++ break;
++ case ROAR_CODEC_OGG_GENERAL:
++ LOG_WARN0("Codec may not work, specify ogg_vorbis for Vorbis streaming");
++ case ROAR_CODEC_OGG_VORBIS:
++ mod->type = ICES_INPUT_VORBIS;
++ // we do not set mod->subtype here, strange design ices2 has...
++ break;
++ case -1:
++ LOG_ERROR0("Unknown Codec");
++ return NULL;
++ default:
++ LOG_ERROR1("Unsupported Codec: %s", roar_codec2str(s->info.codec));
++ return NULL;
++ }
++
++
++ /* Open the VS connection */
++ if ( (s->vss = roar_vs_new(server, "ices2", &err)) == NULL ) {
++ LOG_ERROR2("Failed to open sound server %s: %s",
++ server, roar_vs_strerr(err));
++ goto fail;
++ }
++
++ /* Now, set the required parameters on that device */
++ if ( roar_vs_stream(s->vss, &s->info, dir, &err) == -1 ) {
++ LOG_ERROR2("Failed to create a new stream on sound server %s: %s",
++ server, roar_vs_strerr(err));
++ goto fail;
++ }
++
++ if ( _set_flags(roar_vs_connection_obj(s->vss, NULL), roar_vs_stream_obj(s->vss, NULL),
++ ROAR_FLAG_META, ROAR_RESET_FLAG) != 0 ) {
++ LOG_WARN0("Can not reset metadata flag from stream");
++ }
++
++ /* We're done, and we didn't fail! */
++ LOG_INFO3("Opened sound server at %s at %d channel(s), %d Hz",
++ server, s->info.channels, s->info.rate);
++
++ switch (use_metadata) {
++ case MD_NONE:
++ break;
++ case MD_FILE:
++ LOG_INFO0("Starting metadata update thread");
++ if(ices_config->metadata_filename)
++ thread_create("im_roar-metadata", metadata_thread_signal, mod, 1);
++ else
++ thread_create("im_roar-metadata", metadata_thread_stdin, mod, 1);
++ break;
++ case MD_STREAM:
++ if ( _set_flags(roar_vs_connection_obj(s->vss, NULL), roar_vs_stream_obj(s->vss, NULL),
++ ROAR_FLAG_META, ROAR_SET_FLAG) != 0 ) {
++ LOG_WARN0("Can not set metadata flag from stream");
++ }
++ break;
++ }
++
++ return mod;
++
++fail:
++ close_module(mod); /* safe, this checks for valid contents */
++ return NULL;
++}
++
++
+--- /dev/null
++++ b/src/im_roar.h
+@@ -0,0 +1,33 @@
++/* im_oss.h
++ * - Raw PCM/Ogg Vorbis input from RoarAudio
++ *
++ * Copyright (c) 2001 Michael Smith <msmith at labyrinth.net.au>
++ * Copyright (c) 2009 Philipp Schafft <lion at lion.leolix.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#ifndef __IM_ROAR_H__
++#define __IM_ROAR_H__
++
++#include <thread/thread.h>
++#include <roaraudio.h>
++#include "inputmodule.h"
++
++typedef struct
++{
++ struct roar_audio_info info;
++
++ roar_vs_t * vss;
++
++ char **metadata;
++ int newtrack;
++ mutex_t metadatalock;
++} im_roar_state;
++
++input_module_t *roar_open_module(module_param_t *params);
++
++#endif /* __IM_ROAR_H__ */
+--- a/src/input.c
++++ b/src/input.c
+@@ -19,7 +19,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/types.h>
+-#ifdef HAVE_STDINT_H
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#elif defined(HAVE_STDINT_H)
+ # include <stdint.h>
+ #endif
+ #include <ogg/ogg.h>
+@@ -36,6 +38,10 @@
+ #include "im_playlist.h"
+ #include "im_stdinpcm.h"
+
++#ifdef HAVE_ROARAUDIO
++#include "im_roar.h"
++#endif
++
+ #ifdef HAVE_OSS
+ #include "im_oss.h"
+ #endif
+@@ -77,6 +83,9 @@
+ static module modules[] = {
+ { "playlist", playlist_open_module},
+ { "stdinpcm", stdin_open_module},
++#ifdef HAVE_ROARAUDIO
++ { "roar", roar_open_module},
++#endif
+ #ifdef HAVE_OSS
+ { "oss", oss_open_module},
+ #endif
+@@ -280,6 +289,7 @@
+ int valid_stream = 1;
+ int inc_count;
+ int not_waiting_for_critical;
++ int foundmodule = 0;
+
+ thread_cond_create(&ices_config->queue_cond);
+ thread_cond_create(&ices_config->event_pending_cond);
+@@ -292,6 +302,7 @@
+ {
+ if(!strcmp(ices_config->playlist_module, modules[current_module].name))
+ {
++ foundmodule = 1;
+ inmod = modules[current_module].open(ices_config->module_params);
+ break;
+ }
+@@ -300,8 +311,12 @@
+
+ if(!inmod)
+ {
+- LOG_ERROR1("Couldn't initialise input module \"%s\"",
+- ices_config->playlist_module);
++ if(foundmodule)
++ LOG_ERROR1("Couldn't initialise input module \"%s\"",
++ ices_config->playlist_module);
++ else
++ LOG_ERROR1("No input module named \"%s\" could be found",
++ ices_config->playlist_module);
+ return;
+ }
+
+--- a/src/metadata.c
++++ b/src/metadata.c
+@@ -20,6 +20,9 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <unistd.h>
++#ifdef HAVE_SYS_SELECT_H
++#include <sys/select.h>
++#endif
+
+ #include "cfgparse.h"
+ #include "inputmodule.h"
+--- /dev/null
++++ b/src/output.c
+@@ -0,0 +1,113 @@
++/* output.c
++ * - Manage output instances
++ *
++ * $Id: output.c,v 1.4 2003/03/22 01:14:35 karl Exp $
++ *
++ * Copyright (c) 2001-2002 Michael Smith <msmith at xiph.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <signal.h>
++
++#include <thread/thread.h>
++#include "cfgparse.h"
++#include "input.h"
++#include "stream.h"
++#include "process.h"
++#include "signals.h"
++
++#define MODULE "output/"
++#include "logging.h"
++
++ref_buffer *instance_wait_for_data(instance_t *stream)
++{
++ ref_buffer *buffer;
++ queue_item *old;
++
++ thread_mutex_lock(&stream->queue->lock);
++ while(!stream->queue->head && !ices_config->shutdown && !stream->kill)
++ {
++ thread_mutex_unlock(&stream->queue->lock);
++ thread_cond_wait(&ices_config->queue_cond);
++ thread_mutex_lock(&stream->queue->lock);
++ }
++
++ if(ices_config->shutdown || stream->kill)
++ {
++ LOG_DEBUG0("Shutdown signalled: thread shutting down");
++ thread_mutex_unlock(&stream->queue->lock);
++ return NULL;
++ }
++
++ buffer = stream->queue->head->buf;
++ old = stream->queue->head;
++
++ stream->queue->head = stream->queue->head->next;
++ if(!stream->queue->head)
++ stream->queue->tail = NULL;
++
++ free(old);
++ stream->queue->length--;
++ thread_mutex_unlock(&stream->queue->lock);
++
++ /* ok, we pulled something off the queue and the queue is
++ * now empty - this means we're probably keeping up, so
++ * clear one of the errors. This way, very occasional errors
++ * don't cause eventual shutdown
++ */
++ if(!stream->queue->head && stream->buffer_failures>0)
++ stream->buffer_failures--;
++
++ return buffer;
++}
++
++/* The main loop for each instance. Gets data passed to it from the stream
++ * * manager (which gets it from the input chain), and feeds it out through each
++ * * output chain.
++ * */
++void *ices_instance_output(void *arg)
++{
++ int ret;
++ instance_t *instance = arg;
++ ref_buffer *in, *out;
++
++ /* What is this for?? */
++ signal(SIGPIPE, signal_hup_handler);
++
++ while(1) {
++ in = instance_wait_for_data(instance);
++
++ if(!in)
++ break;
++
++ if(!in->buf || in->len <= 0) {
++ LOG_WARN0("Bad buffer dequeued.");
++ release_buffer(in);
++ continue;
++ }
++
++ ret = process_chain(instance, instance->output_chain, in, &out);
++
++ if(ret == -1) {
++ LOG_DEBUG0("Non-fatal error - chain not completed");
++ continue;
++ }
++ else if(ret == -2) {
++ LOG_ERROR0("Error received from output chain");
++ break;
++ }
++ }
++
++ /* Left main loop, we've shut down */
++ instance->died = 1;
++
++ return NULL;
++}
++
+--- a/src/playlist_basic.c
++++ b/src/playlist_basic.c
+@@ -125,7 +125,7 @@
+ char *playlist_basic_get_next_filename(void *data)
+ {
+ basic_playlist *pl = (basic_playlist *)data;
+- char *ptr = NULL, *dest = NULL;
++ char *ptr = NULL;
+ int reload_playlist = 0;
+ struct stat st;
+
+@@ -171,10 +171,7 @@
+
+ ptr = pl->pl [pl->pos++];
+
+- if ((dest = malloc (strlen (ptr)+1)) == NULL)
+- return NULL;
+- strcpy (dest, ptr);
+- return dest;
++ return strdup(ptr);
+ }
+
+ void playlist_basic_free_filename(void *data, char *fn)
+--- /dev/null
++++ b/src/process.c
+@@ -0,0 +1,155 @@
++/* process.c
++ * - Processing chains - data sources, sinks, processing effects, reencoding,
++ * etc.
++ *
++ * $Id: process.c,v 1.4 2003/03/16 14:21:49 msmith Exp $
++ *
++ * Copyright (c) 2001-2002 Michael Smith <msmith at xiph.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++
++#include "process.h"
++#include "config.h"
++#include "thread/thread.h"
++
++#define MODULE "process/"
++#include "logging.h"
++
++#define DEBUG_BUFFERS
++
++
++/* Return a newly allocate buffer, with refcount initialised to 1. */
++ref_buffer *new_ref_buffer(media_type media, void *data, int len, int aux)
++{
++ ref_buffer *new = calloc(1, sizeof(ref_buffer) + (sizeof(int)*(aux-1)));
++ new->type = media;
++ new->buf = data;
++ new->len = len;
++
++ new->count = 1;
++
++ return new;
++}
++
++void acquire_buffer(ref_buffer *buf)
++{
++ thread_mutex_lock(&ices_config->refcount_lock);
++
++#ifdef DEBUG_BUFFERS
++ if(!buf) {
++ LOG_ERROR0("Null buffer aquired?");
++ thread_mutex_unlock(&ices_config->refcount_lock);
++ return;
++ }
++ if(buf->count < 0)
++ LOG_ERROR1("Error: refbuf has count %d before increment.", buf->count);
++#endif
++
++ buf->count++;
++
++ thread_mutex_unlock(&ices_config->refcount_lock);
++}
++
++void release_buffer(ref_buffer *buf)
++{
++ thread_mutex_lock(&ices_config->refcount_lock);
++
++#ifdef DEBUG_BUFFERS
++ if(!buf) {
++ LOG_ERROR0("Null buffer released?");
++ thread_mutex_unlock(&ices_config->refcount_lock);
++ return;
++ }
++ if(buf->count <= 0)
++ LOG_ERROR1("Error: refbuf has count %d before decrement.", buf->count);
++#endif
++
++ buf->count--;
++
++ if(!buf->count)
++ {
++ free(buf->buf);
++ free(buf);
++ }
++ thread_mutex_unlock(&ices_config->refcount_lock);
++}
++
++/* return values:
++ * 0: normal return, success.
++ * -1: chain terminated - insufficient data available?
++ * -2: fatal error.
++ */
++
++int process_chain(instance_t *instance, process_chain_element *chain,
++ ref_buffer *in, ref_buffer **out)
++{
++ int ret=0;
++
++ while(chain) {
++ if(chain->input_type != MEDIA_NONE && !in) {
++ LOG_ERROR0("NULL input buffer where input required.");
++ return -2;
++ }
++ else if(chain->input_type != MEDIA_NONE && chain->input_type !=
++ MEDIA_DATA && in->type != chain->input_type) {
++ LOG_ERROR2("Chain input does not match expected input! (%d != %d)",
++ in->type, chain->input_type);
++ return -2;
++ }
++
++ ret = chain->process(instance, chain->priv_data, in, out);
++
++ if(ret <= 0) {
++ return ret;
++ }
++
++ if(chain->output_type != MEDIA_NONE && chain->output_type != MEDIA_DATA
++ && (*out)->type != chain->output_type) {
++ LOG_ERROR0("Chain did not produce expected output type.");
++ return -2;
++ }
++
++ in = *out;
++ chain = chain->next;
++ }
++
++ return ret;
++}
++
++void create_event(process_chain_element *chain, event_type event,
++ void *param, int broadcast)
++{
++ /* chain->handle_event() returns 0 if it handles the event successfully.
++ * We deliver to only one chain object unless the broadcast flag is set.
++ */
++
++ /* XXX: Try something like this?? Wake threads that don't do anything
++ * except when a flag gets set like this.
++ * if(!chain) {
++ * thread_cond_broadcast(&ices_config->event_pending_cond);
++ * } else { ...
++ */
++ while(chain) {
++ if(!(chain->event_handler(chain, event, param) || broadcast))
++ return;
++
++ chain = chain->next;
++ }
++
++ if(!broadcast)
++ LOG_INFO1("Non-broadcast event %d unhandled", event);
++}
++
++
++
++
+--- /dev/null
++++ b/src/process.h
+@@ -0,0 +1,109 @@
++/* process.h
++ * - Processing chains
++ *
++ * $Id: process.h,v 1.3 2003/03/16 14:21:49 msmith Exp $
++ *
++ * Copyright (c) 2001-2002 Michael Smith <msmith at xiph.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#ifndef __PROCESS_H__
++#define __PROCESS_H__
++
++#include "event.h"
++
++typedef enum {
++ MEDIA_VORBIS,
++ MEDIA_PCM,
++ MEDIA_DATA,
++ MEDIA_NONE,
++} media_type;
++
++typedef enum {
++ SUBTYPE_PCM_BE_16,
++ SUBTYPE_PCM_LE_16,
++ SUBTYPE_PCM_FLOAT,
++} media_subtype;
++
++typedef enum {
++ FLAG_CRITICAL = 1<<0,
++ FLAG_BOS = 1<<1,
++
++} buffer_flags;
++
++typedef struct {
++ media_type type; /* Type of data held in buffer */
++ media_subtype subtype;
++ short channels;
++ int rate;
++
++ void *buf; /* Actual data */
++ int len; /* Length of data (usually bytes, sometimes samples */
++
++ short count; /* Reference count */
++
++ buffer_flags flags; /* Flag: critical chunks must be processed fully */
++ int aux_data_len;
++ long aux_data[1]; /* Auxilliary data used for various purposes */
++} ref_buffer;
++
++/* Need some forward declarations */
++struct _process_chain_element;
++struct _instance_t;
++struct _module_param_t;
++
++/* Note that instance will be NULL for input chains */
++typedef int (*process_func)(struct _instance_t *instance, void *data,
++ ref_buffer *in, ref_buffer **out);
++typedef int (*event_func)(struct _process_chain_element *self, event_type event,
++ void *param);
++typedef int (*open_func)(struct _process_chain_element *self,
++ struct _module_param_t *params);
++
++typedef struct _process_chain_element {
++ char *name;
++ open_func open;
++ struct _module_param_t *params;
++
++ process_func process;
++ event_func event_handler;
++ void *priv_data;
++
++ media_type input_type;
++ media_type output_type;
++
++ struct _process_chain_element *next;
++} process_chain_element;
++
++typedef struct _instance_t
++{
++ int buffer_failures;
++ int died;
++ int kill;
++ int skip;
++ int wait_for_critical;
++
++ struct buffer_queue *queue;
++ int max_queue_length;
++ process_chain_element *output_chain;
++
++ struct _instance_t *next;
++} instance_t;
++
++int process_chain(struct _instance_t *instance, process_chain_element *chain,
++ ref_buffer *in, ref_buffer **out);
++
++ref_buffer *new_ref_buffer(media_type media, void *data, int len, int aux);
++void acquire_buffer(ref_buffer *buf);
++void release_buffer(ref_buffer *buf);
++
++void create_event(process_chain_element *chain, event_type event, void *param,
++ int broadcast);
++
++#endif /* __PROCESS_H__ */
++
++
+--- /dev/null
++++ b/src/registry.h
+@@ -0,0 +1,65 @@
++/* registry.h
++ * - Registry of input/output/processing modules.
++ *
++ * $Id: registry.h,v 1.3 2002/12/29 10:28:30 msmith Exp $
++ *
++ * Copyright (c) 2001-2002 Michael Smith <msmith at xiph.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#ifndef __REGISTRY_H__
++#define __REGISTRY_H__
++
++#include "process.h"
++#include "config.h"
++#include "im_playlist.h"
++#include "im_stdinpcm.h"
++#include "stream.h"
++#include "encode.h"
++
++#ifdef HAVE_OSS
++#include "im_oss.h"
++#endif
++
++#ifdef HAVE_ALSA
++#include "im_alsa.h"
++#endif
++
++/*
++#ifdef HAVE_SUN_AUDIO
++#include "im_sun.h"
++#endif
++*/
++typedef struct _module
++{
++ char *name;
++ open_func open;
++} module;
++
++/* Some others we don't have headers for */
++int savefile_open_module(process_chain_element *mod, module_param_t *params);
++
++static module registered_modules[] = {
++ { "encode", encode_open_module},
++ { "stream", stream_open_module},
++ { "playlist", playlist_open_module},
++ { "stdinpcm", stdin_open_module},
++ { "savestream", savefile_open_module},
++#ifdef HAVE_OSS
++ { "oss", oss_open_module},
++#endif
++#ifdef HAVE_SUN_AUDIO
++ { "sun", sun_open_module},
++#endif
++#ifdef HAVE_ALSA
++ { "alsa", alsa_open_module},
++#endif
++ {NULL,NULL}
++};
++
++#endif /* __REGISTRY_H__ */
++
+--- /dev/null
++++ b/src/savefile.c
+@@ -0,0 +1,89 @@
++/* savefile.c
++ * - Stream saving to file.
++ *
++ * $Id: savefile.c,v 1.4 2003/03/16 14:21:49 msmith Exp $
++ *
++ * Copyright (c) 2001 Michael Smith <msmith at xiph.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ *
++ * NOTE: Not currently actually used.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++
++#include "config.h"
++#include "input.h"
++#include "inputmodule.h"
++#include "stream_shared.h"
++#include "stream.h"
++
++#define MODULE "stream-save/"
++#include "logging.h"
++
++
++void *savefile_stream(void *arg)
++{
++ stream_description *sdsc = arg;
++ instance_t *stream = sdsc->stream;
++ ref_buffer *buf;
++ FILE *file;
++ int ret;
++ char *filename = stream->savefilename;
++
++ /* FIXME: Check for file existence, and append some unique string
++ * if it already exists.
++ */
++ file = fopen(filename, "wb");
++
++ if(!file)
++ {
++ LOG_ERROR1("Couldn't open file to save stream: %s", filename);
++ stream->died = 1;
++ return NULL;
++ }
++
++ LOG_INFO1("Saving stream to file: %s", filename);
++
++ while(1)
++ {
++ buf = stream_wait_for_data(stream);
++
++ if(!buf)
++ break;
++
++ if(!buf->buf || !buf->len)
++ {
++ LOG_WARN0("Bad buffer dequeue, not saving");
++ continue;
++ }
++
++ ret = fwrite(buf->buf, 1, buf->len, file);
++
++ if(ret != buf->len)
++ {
++ LOG_ERROR1("Error writing to file: %s", strerror(errno));
++ /* FIXME: Try writing to a new file, or something */
++ break;
++ }
++
++ stream_release_buffer(buf);
++ }
++
++ fclose(file);
++
++ stream->died = 1;
++ return NULL;
++}
++
++
++
++
++
+--- a/src/stream.c
++++ b/src/stream.c
+@@ -291,13 +291,16 @@
+ input_flush_queue(stream->queue, 1);
+ thread_mutex_unlock(&ices_config->flush_lock);
+
++ shout_close(sdsc->shout);
++
++ if (i >= stream->reconnect_attempts)
++ break;
+ while((i < stream->reconnect_attempts ||
+ stream->reconnect_attempts==-1) &&
+ !ices_config->shutdown)
+ {
+- i++;
+ LOG_WARN0("Trying reconnect after server socket error");
+- shout_close(sdsc->shout);
++ i++;
+ if((shouterr = shout_open(sdsc->shout)) == SHOUTERR_SUCCESS)
+ {
+ LOG_INFO3("Connected to server: %s:%d%s",
+@@ -312,6 +315,7 @@
+ thread_mutex_lock(&ices_config->flush_lock);
+ stream->wait_for_critical = 1;
+ input_flush_queue(stream->queue, 0);
++ stream->skip = 0;
+ thread_mutex_unlock(&ices_config->flush_lock);
+ break;
+ }
+@@ -331,7 +335,6 @@
+ thread_sleep (stream->reconnect_delay*1000000);
+ }
+ }
+- stream->skip = 0;
+ }
+ stream->buffer_failures++;
+ }
+--- /dev/null
++++ b/src/stream_rewrite.c
+@@ -0,0 +1,251 @@
++/* stream_rewrite.c
++ * - Functions to rewrite a stream (at the ogg level) at runtime, to
++ * allow a) More reliable streaming of somewhat broken files, and
++ * b) Inserting comments into 'static' files at stream time.
++ *
++ * Heavily based on vcedit.c from vorbiscomment.
++ *
++ * $Id: stream_rewrite.c,v 1.4 2003/03/16 14:21:49 msmith Exp $
++ *
++ * Copyright (c) 2001 Michael Smith <msmith at xiph.org>
++ *
++ * This program is distributed under the terms of the GNU General
++ * Public License, version 2. You may use, modify, and redistribute
++ * it under the terms of this license. A copy should be included
++ * with this source.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <ogg/ogg.h>
++#include <vorbis/codec.h>
++
++#include "config.h"
++//#include "stream_rewrite.h"
++
++typedef struct {
++ ogg_sync_state sync;
++ ogg_stream_state stream_out;
++ ogg_stream_state stream_in;
++
++ vorbis_comment vc;
++ vorbis_info vi;
++
++ FILE *in;
++ long serial;
++ char *vendor;
++ int prevW;
++
++ short needflush,needout,in_header;
++
++ ogg_int64_t granpos;
++
++} stream_rewriter;
++
++#define MODULE "stream-rewrite/"
++#include "logging.h"
++
++#define CHUNKSIZE 4096
++
++/* Next two functions pulled straight from libvorbis, apart from one change
++ * - we don't want to overwrite the vendor string.
++ */
++static void _v_writestring(oggpack_buffer *o,char *s, int len)
++{
++ while(len--)
++ {
++ oggpack_write(o,*s++,8);
++ }
++}
++
++static int _commentheader_out(vorbis_comment *vc, char *vendor, ogg_packet *op)
++{
++ oggpack_buffer opb;
++
++ oggpack_writeinit(&opb);
++
++ /* preamble */
++ oggpack_write(&opb,0x03,8);
++ _v_writestring(&opb,"vorbis", 6);
++
++ /* vendor */
++ oggpack_write(&opb,strlen(vendor),32);
++ _v_writestring(&opb,vendor, strlen(vendor));
++
++ /* comments */
++ oggpack_write(&opb,vc->comments,32);
++ if(vc->comments){
++ int i;
++ for(i=0;i<vc->comments;i++){
++ if(vc->user_comments[i]){
++ oggpack_write(&opb,vc->comment_lengths[i],32);
++ _v_writestring(&opb,vc->user_comments[i], vc->comment_lengths[i]);
++ }else{
++ oggpack_write(&opb,0,32);
++ }
++ }
++ }
++ oggpack_write(&opb,1,1);
++
++ op->packet = _ogg_malloc(oggpack_bytes(&opb));
++ memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));
++
++ op->bytes=oggpack_bytes(&opb);
++ op->b_o_s=0;
++ op->e_o_s=0;
++ op->granulepos=0;
++
++ return 0;
++}
++
++static int _blocksize(stream_rewriter *s, ogg_packet *p)
++{
++ int this = vorbis_packet_blocksize(&s->vi, p);
++ int ret = (this + s->prevW)/4;
++
++ if(!s->prevW)
++ {
++ s->prevW = this;
++ return 0;
++ }
++
++ s->prevW = this;
++ return ret;
++}
++
++static int _fetch_next_packet(stream_rewriter *s, ogg_packet *p)
++{
++ int result;
++ ogg_page og;
++ char *buffer;
++ int bytes;
++
++ result = ogg_stream_packetout(&s->stream_in, p);
++
++ if(result > 0)
++ return 1;
++ else
++ {
++ while(ogg_sync_pageout(&s->sync, &og) <= 0)
++ {
++ buffer = ogg_sync_buffer(&s->sync, CHUNKSIZE);
++ bytes = fread(buffer,1, CHUNKSIZE, s->in);
++ ogg_sync_wrote(&s->sync, bytes);
++ if(bytes == 0)
++ return 0;
++ }
++
++ ogg_stream_pagein(&s->stream_in, &og);
++ return _fetch_next_packet(s, p);
++ }
++}
++
++static int _get_next_page(stream_rewriter *s, ogg_page *page)
++{
++ if(s->needflush)
++ {
++ if(ogg_stream_flush(&s->stream_out, page))
++ {
++ s->needflush=s->needout=0;
++ return 1;
++ }
++ }
++ else if(s->needout)
++ {
++ if(ogg_stream_pageout(&s->stream_out, page))
++ {
++ s->needflush=s->needout=0;
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++/* (what does this do?)
++ * return value: <0 Error
++ * 0 No more data in current file
++ * >0 Success, page returned.
++ */
++int stream_get_page(stream_rewriter *s, ogg_page *page)
++{
++ int res;
++ ogg_packet packet;
++
++ /* See if there's a pending page already - this should do the stuff with
++ * needflush/needout, remove that from below */
++ if(_get_next_page(s, page) > 0)
++ return 1;
++
++ while((_fetch_next_packet(s, &packet) > 0))
++ {
++ /* Ok, deal with all the icky granulepos manipulations we need */
++ int size = _blocksize(s, &packet);
++ int flag=0;
++ s->granpos += size;
++
++ if(_get_next_page(s, page) > 0)
++ flag = 1;
++
++ if(packet.granulepos == -1)
++ packet.granulepos = s->granpos;
++ else
++ {
++ if(s->granpos > packet.granulepos)
++ {
++ s->granpos = packet.granulepos;
++ s->needflush = 1;
++ }
++ else
++ s->needout = 1;
++ }
++
++ /* Header packet. Note that this doesn't catch ALL header packets
++ * (some dodgy files have it wrong, it catches them all in correct
++ * streams), but it always gets the first packet (primary header)
++ */
++ if(packet.granulepos == 0)
++ {
++ s->in_header = 1;
++ s->needflush = 1;
++
++ ogg_stream_init(&s->stream_out, s->serial++);
++ vorbis_info_init(&s->vi);
++ vorbis_comment_init(&s->vc);
++ }
++
++ if(s->in_header)
++ {
++ if(vorbis_synthesis_headerin(&s->vi, &s->vc, &packet) < 0)
++ {
++ LOG_ERROR0("Bad header in vorbis bitstream, cannot send");
++ /* FIXME: Clear allocations first */
++ return -1;
++ }
++
++ if(s->in_header++ == 3) /* We have all 3 header packets */
++ {
++ s->in_header = 0;
++ s->needflush = 1;
++ }
++
++ /* FIXME: Allow comment header mangling here */
++ }
++
++ ogg_stream_packetin(&s->stream_out, &packet);
++
++ if(flag == 1)
++ return 1;
++ }
++
++ /* Fall out of above loop means EOS. Try flushing output stream */
++ s->stream_out.e_o_s = 1;
++ if(ogg_stream_flush(&s->stream_out, page))
++ return 1;
++
++ /* Final fallthrough. Nothing left. At all.
++ * FIXME: cope with chained streams properly. */
++ return 0;
++}
++
diff --git a/debian/patches/series b/debian/patches/series
index 836ba75..36a7494 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,4 +1,4 @@
-0001_sync_20090819.patch
+0001_sync_upstream_VCS.patch
1001_allow_repeat.patch
1002_fix_OSS-ALSA_confusion_in_comments.patch
1003_no_Makefile_in_debian_subdir.patch
--
ices2 packaging
More information about the pkg-multimedia-commits
mailing list