[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