[xiph-commits] r9406 - in icecast/trunk/icecast: doc src

karl at motherfish-iii.xiph.org karl at motherfish-iii.xiph.org
Wed Jun 8 18:51:54 PDT 2005


Author: karl
Date: 2005-06-08 18:51:47 -0700 (Wed, 08 Jun 2005)
New Revision: 9406

Modified:
   icecast/trunk/icecast/doc/icecast2_config_file.html
   icecast/trunk/icecast/src/admin.c
   icecast/trunk/icecast/src/cfgfile.c
   icecast/trunk/icecast/src/cfgfile.h
   icecast/trunk/icecast/src/connection.c
   icecast/trunk/icecast/src/format.c
   icecast/trunk/icecast/src/slave.c
   icecast/trunk/icecast/src/slave.h
   icecast/trunk/icecast/src/source.c
   icecast/trunk/icecast/src/source.h
Log:
merge in the on-demand relay implementation.


Modified: icecast/trunk/icecast/doc/icecast2_config_file.html
===================================================================
--- icecast/trunk/icecast/doc/icecast2_config_file.html	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/doc/icecast2_config_file.html	2005-06-09 01:51:47 UTC (rev 9406)
@@ -210,6 +210,7 @@
     <master-update-interval>120</master-update-interval>
     <master-username>relay</master-username>
     <master-password>hackme</master-password>
+    <relays-on-demand>0</relays-on-demand>
 
     <relay>
         <server>127.0.0.1</server>
@@ -219,6 +220,7 @@
         <username>joe</username>
         <password>soap</password>
         <relay-shoutcast-metadata>0</relay-shoutcast-metadata>
+        <on-demand>0</on-demand>
     </relay>
 </pre>
 <p>This section contains the server's relay settings. There are two types of relays: a "Master server relay" or a "Specific Mountpoint relay."  A Master server relay is only supported between icecast2 servers and is used to relays all mountpoints on a remote icecast2 server.   
@@ -268,6 +270,13 @@
 This is the relay password on the Master server.  It is used to query the
 server for a list of mountpoints to relay.
 </div>
+<h4>relays-on-demand</h4>
+<div class="indentedbox">
+    <p>Changes the default on-demand setting for relays, so a stream is only relayed if
+    listeners are connected. 1=enabled, 0=disabled (default).
+    </p>
+</div>
+
 <br />
 <h3>Specific Mountpoint Relay</h3>
 The following diagram shows the basics of doing a Specific Mountpoint relay.  Note that Server 1 is configured with the &lt;relay&gt; settings and Server 2 is the server from which Server 1 will pull the specified mountpoint(s) and relay them.  Using a Specific Mountpoint Relay, only those mountpoints specified on Server 1 will be relayed from Server 2.
@@ -299,6 +308,7 @@
         &lt;username&gt;joe&lt;/username&gt;
         &lt;password&gt;soap&lt;/password&gt;
         &lt;relay-shoutcast-metadata&gt;0&lt;/relay-shoutcast-metadata&gt;
+        &lt;on-demand&gt;1&lt;/on-demand&gt;
     &lt;/relay&gt;
 </pre>
 
@@ -331,6 +341,13 @@
 <div class="indentedbox">
 If you are relaying a Shoutcast stream, you need to specify this indicator to also relay the metadata (song titles) that is part of the Shoutcast stream (1=enabled, 0=disabled).
 </div>
+<h4>on-demand</h4>
+<div class="indentedbox">
+    <p>An on-demand relay will only retrieve the stream if there are listeners connected
+    1=enabled, 0=disabled (default is &lt;relays-on-demand&gt;).
+    </p>
+</div>
+
 <p>
 <br />
 <br />
@@ -405,7 +422,6 @@
     being opened.
     </p>
 </div>
-
 <h4>fallback-mount</h4>
 <div class="indentedbox">
 This optional value specifies a mountpoint that clients are automatically moved to if the source
@@ -492,10 +508,11 @@
 </div>
 <h4>mp3-metadata-interval</h4>
 <div class="indentedbox">
-This optional setting specifies what interval, in bytes, there is between metadata updates within
-shoutcast compatible streams. This only applies to new listeners connecting on this mountpoint,
-not existing listeners falling back to this mountpoint.  The default is either the hardcoded
-server default or the value passed from a relay.
+    <p>This optional setting specifies what interval, in bytes, there is between metadata
+    updates within shoutcast compatible streams. This only applies to new listeners connecting
+    on this mountpoint, not existing listeners falling back to this mountpoint.  The default
+    is either the hardcoded server default or the value passed from a relay.
+    </p>
 </div>
 <h4>hidden</h4>
 <div class="indentedbox">

Modified: icecast/trunk/icecast/src/admin.c
===================================================================
--- icecast/trunk/icecast/src/admin.c	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/admin.c	2005-06-09 01:51:47 UTC (rev 9406)
@@ -226,7 +226,7 @@
             continue;
         }
 
-        if (source->running)
+        if (source->running || source->on_demand)
         {
             srcnode = xmlNewChild(xmlnode, NULL, "source", NULL);
             xmlSetProp(srcnode, "mount", source->mount);
@@ -369,7 +369,7 @@
         }
         else
         {
-            if (source->running == 0)
+            if (source->running == 0 && source->on_demand == 0)
             {
                 avl_tree_unlock (global.source_tree);
                 INFO2("Received admin command %s on unavailable mount \"%s\"",
@@ -590,7 +590,7 @@
         return;
     }
 
-    if (dest->running == 0)
+    if (dest->running == 0 && dest->on_demand == 0)
     {
         client_send_400 (client, "Destination not running");
         return;
@@ -982,7 +982,7 @@
 
             if (source == NULL)
                 continue;
-            if (source->running == 0)
+            if (source->running == 0 && source->on_demand == 0)
                 continue;
             if (source->hidden)
                 continue;

Modified: icecast/trunk/icecast/src/cfgfile.c
===================================================================
--- icecast/trunk/icecast/src/cfgfile.c	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/cfgfile.c	2005-06-09 01:51:47 UTC (rev 9406)
@@ -342,6 +342,7 @@
     configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
     configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
     configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
+    configuration->on_demand = 0;
     configuration->dir_list = NULL;
     configuration->hostname = CONFIG_DEFAULT_HOSTNAME;
     configuration->port = 0;
@@ -408,6 +409,10 @@
             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
             configuration->fileserve = atoi(tmp);
             if (tmp) xmlFree(tmp);
+        } else if (strcmp(node->name, "relays-on-demand") == 0) {
+            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+            configuration->on_demand = atoi(tmp);
+            if (tmp) xmlFree(tmp);
         } else if (strcmp(node->name, "hostname") == 0) {
             if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname);
             configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
@@ -697,6 +702,7 @@
 
     relay->next = NULL;
     relay->mp3metadata = 1;
+    relay->on_demand = configuration->on_demand;
 
     do {
         if (node == NULL) break;
@@ -732,6 +738,11 @@
             relay->password = (char *)xmlNodeListGetString(doc,
                     node->xmlChildrenNode, 1);
         }
+        else if (strcmp(node->name, "on-demand") == 0) {
+            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+            relay->on_demand = atoi(tmp);
+            if (tmp) xmlFree(tmp);
+        }
     } while ((node = node->next));
     if (relay->localmount == NULL)
         relay->localmount = xmlStrdup (relay->mount);

Modified: icecast/trunk/icecast/src/cfgfile.h
===================================================================
--- icecast/trunk/icecast/src/cfgfile.h	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/cfgfile.h	2005-06-09 01:51:47 UTC (rev 9406)
@@ -109,6 +109,7 @@
     int source_timeout;
     int ice_login;
     int fileserve;
+    int on_demand; /* global setting for all relays */
 
     char *shoutcast_mount;
     char *source_password;

Modified: icecast/trunk/icecast/src/connection.c
===================================================================
--- icecast/trunk/icecast/src/connection.c	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/connection.c	2005-06-09 01:51:47 UTC (rev 9406)
@@ -896,7 +896,7 @@
             if (uri != passed_uri) free (uri);
             return;
         }
-        if (source->running == 0)
+        if (source->running == 0 && source->on_demand == 0)
         {
             avl_tree_unlock(global.source_tree);
             DEBUG0("inactive source, client dropped");
@@ -953,6 +953,14 @@
         avl_tree_wlock(source->pending_tree);
         avl_insert(source->pending_tree, (void *)client);
         avl_tree_unlock(source->pending_tree);
+
+        if (source->running == 0 && source->on_demand)
+        {
+            /* enable on-demand relay to start, wake up the slave thread */
+            DEBUG0("kicking off on-demand relay");
+            source->on_demand_req = 1;
+            slave_rescan ();
+        }
     }
                     
     avl_tree_unlock(global.source_tree);

Modified: icecast/trunk/icecast/src/format.c
===================================================================
--- icecast/trunk/icecast/src/format.c	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/format.c	2005-06-09 01:51:47 UTC (rev 9406)
@@ -114,6 +114,7 @@
         {
             client_set_queue (client, refbuf);
             client->check_buffer = format_advance_queue;
+            client->write_to_client = source->format->write_buf_to_client;
             client->intro_offset = -1;
             break;
         }

Modified: icecast/trunk/icecast/src/slave.c
===================================================================
--- icecast/trunk/icecast/src/slave.c	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/slave.c	2005-06-09 01:51:47 UTC (rev 9406)
@@ -99,6 +99,7 @@
             copy->password = xmlStrdup (r->password);
         copy->port = r->port;
         copy->mp3metadata = r->mp3metadata;
+        copy->on_demand = r->on_demand;
     }
     return copy;
 }
@@ -114,6 +115,15 @@
 }
 
 
+/* Request slave thread to rescan the existing relays to see if any need
+ * starting up, eg on-demand relays
+ */
+void slave_rescan (void)
+{
+    rescan_relays = 1;
+}
+
+
 /* Request slave thread to check the relay list for changes and to
  * update the stats for the current streams.
  */
@@ -235,6 +245,13 @@
 
         source_main (relay->source);
 
+        if (relay->on_demand == 0)
+        {
+            /* only keep refreshing YP entries for inactive on-demand relays */
+            yp_remove (relay->localmount);
+            relay->source->yp_public = -1;
+        }
+
         /* initiate an immediate relay cleanup run */
         relay->cleanup = 1;
         rescan_relays = 1;
@@ -242,6 +259,20 @@
         return NULL;
     } while (0);
 
+    DEBUG1 ("failed relay, fallback to %s", relay->source->fallback_mount);
+    if (relay->source->fallback_mount)
+    {
+        source_t *fallback_source;
+
+        avl_tree_rlock(global.source_tree);
+        fallback_source = source_find_mount (relay->source->fallback_mount);
+
+        if (fallback_source != NULL)
+            source_move_clients (relay->source, fallback_source);
+
+        avl_tree_unlock (global.source_tree);
+    }
+
     if (con == NULL && streamsock != SOCK_ERROR)
         sock_close (streamsock);
     if (con)
@@ -278,13 +309,46 @@
         else
             WARN1 ("new relay but source \"%s\" already exists", relay->localmount);
     }
-    if (relay->source && !relay->running)
+    do
     {
+        source_t *source = relay->source;
+        if (relay->source == NULL || relay->running)
+            break;
+        if (relay->on_demand)
+        {
+            ice_config_t *config = config_get_config ();
+            mount_proxy *mountinfo = config_find_mount (config, relay->localmount);
+
+            if (mountinfo == NULL)
+                source_update_settings (config, relay->source, mountinfo);
+            config_release_config ();
+            slave_rebuild_mounts();
+            stats_event (relay->localmount, "listeners", "0");
+            relay->source->on_demand = relay->on_demand;
+
+            if (source->fallback_mount && source->fallback_override)
+            {
+                source_t *fallback;
+                DEBUG1 ("checking %s for fallback override", source->fallback_mount);
+                avl_tree_rlock (global.source_tree);
+                fallback = source_find_mount (source->fallback_mount);
+                if (fallback && fallback->running && fallback->listeners)
+                {
+                   DEBUG2 ("fallback running %d with %lu listeners", fallback->running, fallback->listeners);
+                   source->on_demand_req = 1;
+                }
+                avl_tree_unlock (global.source_tree);
+            }
+            if (source->on_demand_req == 0)
+                break;
+        }
+
         relay->thread = thread_create ("Relay Thread", start_relay_stream,
                 relay, THREAD_ATTACHED);
         return;
-    }
-    /* the relay thread may of close down */
+
+    } while(0);
+    /* the relay thread may of shut down itself */
     if (relay->cleanup && relay->thread)
     {
         DEBUG1 ("waiting for relay thread for \"%s\"", relay->localmount);
@@ -292,6 +356,15 @@
         relay->thread = NULL;
         relay->cleanup = 0;
         relay->running = 0;
+
+        if (relay->on_demand)
+        {
+            ice_config_t *config = config_get_config ();
+            mount_proxy *mountinfo = config_find_mount (config, relay->localmount);
+            source_update_settings (config, relay->source, mountinfo);
+            config_release_config ();
+            stats_event (relay->localmount, "listeners", "0");
+        }
     }
 }
 
@@ -311,6 +384,8 @@
             break;
         if (new->mp3metadata != old->mp3metadata)
             break;
+        if (new->on_demand != old->on_demand)
+            old->on_demand = new->on_demand;
         return 0;
     } while (0);
     return 1;
@@ -421,6 +496,7 @@
         char *authheader, *data;
         relay_server *new_relays = NULL, *cleanup_relays;
         int len, count = 1;
+        int on_demand;
 
         username = strdup (config->master_username);
         if (config->master_password)
@@ -433,6 +509,7 @@
 
         if (password == NULL || master == NULL || port == 0)
             break;
+        on_demand = config->on_demand;
         ret = 1;
         config_release_config();
         mastersock = sock_connect_wto (master, port, 0);
@@ -481,6 +558,7 @@
                 r->mount = xmlStrdup (buf);
                 r->localmount = xmlStrdup (buf);
                 r->mp3metadata = 1;
+                r->on_demand = on_demand;
                 r->next = new_relays;
                 new_relays = r;
             }

Modified: icecast/trunk/icecast/src/slave.h
===================================================================
--- icecast/trunk/icecast/src/slave.h	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/slave.h	2005-06-09 01:51:47 UTC (rev 9406)
@@ -24,6 +24,7 @@
     char *localmount;
     struct source_tag *source;
     int mp3metadata;
+    int on_demand;
     int running;
     int cleanup;
     thread_type *thread;
@@ -35,6 +36,7 @@
 void slave_shutdown(void);
 void slave_recheck_mounts (void);
 void slave_rebuild_mounts (void);
+void slave_rescan (void);
 relay_server *relay_free (relay_server *relay);
 
 #endif  /* __SLAVE_H__ */

Modified: icecast/trunk/icecast/src/source.c
===================================================================
--- icecast/trunk/icecast/src/source.c	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/source.c	2005-06-09 01:51:47 UTC (rev 9406)
@@ -152,8 +152,11 @@
     {
         source = source_find_mount_raw(mount);
 
-        if (source != NULL && source->running)
-            break;
+        if (source)
+        {
+            if (source->running || source->on_demand)
+                break;
+        }
 
         /* we either have a source which is not active (relay) or no source
          * at all. Check the mounts list for fallback settings
@@ -229,9 +232,6 @@
     }
     source->stream_data_tail = NULL;
 
-    if (source->yp_public)
-        yp_remove (source->mount);
-
     source->burst_point = NULL;
     source->burst_size = 0;
     source->burst_offset = 0;
@@ -257,6 +257,8 @@
         fclose (source->intro_file);
         source->intro_file = NULL;
     }
+
+    source->on_demand_req = 0;
 }
 
 
@@ -271,6 +273,9 @@
     avl_tree_free(source->pending_tree, _free_client);
     avl_tree_free(source->client_tree, _free_client);
 
+    /* make sure all YP entries have gone */
+    yp_remove (source->mount);
+
     free (source->mount);
     free (source);
 
@@ -306,6 +311,7 @@
  */
 void source_move_clients (source_t *source, source_t *dest)
 {
+    unsigned long count = 0;
     if (strcmp (source->mount, dest->mount) == 0)
     {
         WARN1 ("src and dst are the same \"%s\", skipping", source->mount);
@@ -316,7 +322,7 @@
 
     /* if the destination is not running then we can't move clients */
 
-    if (dest->running == 0)
+    if (dest->running == 0 && dest->on_demand == 0)
     {
         WARN1 ("destination mount %s not running, unable to move clients ", dest->mount);
         thread_mutex_unlock (&move_clients_mutex);
@@ -331,15 +337,18 @@
         /* we need to move the client and pending trees */
         avl_tree_wlock (source->pending_tree);
 
-        if (source->format == NULL)
+        if (source->on_demand == 0 && source->format == NULL)
         {
             INFO1 ("source mount %s is not available", source->mount);
             break;
         }
-        if (source->format->type != dest->format->type)
+        if (source->format && dest->format)
         {
-            WARN2 ("stream %s and %s are of different types, ignored", source->mount, dest->mount);
-            break;
+            if (source->format->type != dest->format->type)
+            {
+                WARN2 ("stream %s and %s are of different types, ignored", source->mount, dest->mount);
+                break;
+            }
         }
 
         while (1)
@@ -350,10 +359,18 @@
             client = (client_t *)(node->key);
             avl_delete (source->pending_tree, client, NULL);
 
-            /* switch client to different queue */
-            client_set_queue (client, NULL);
-            client->check_buffer = format_check_file_buffer;
+            /* when switching a client to a different queue, be wary of the 
+             * refbuf it's referring to, if it's http headers then we need
+             * to write them so don't release it.
+             */
+            if (client->check_buffer != format_check_http_buffer)
+            {
+                client_set_queue (client, NULL);
+                client->check_buffer = format_check_file_buffer;
+            }
+
             avl_insert (dest->pending_tree, (void *)client);
+            count++;
         }
 
         avl_tree_wlock (source->client_tree);
@@ -366,17 +383,33 @@
             client = (client_t *)(node->key);
             avl_delete (source->client_tree, client, NULL);
 
-            /* switch client to different queue */
-            client_set_queue (client, NULL);
-            client->check_buffer = format_check_file_buffer;
+            /* when switching a client to a different queue, be wary of the 
+             * refbuf it's referring to, if it's http headers then we need
+             * to write them so don't release it.
+             */
+            if (client->check_buffer != format_check_http_buffer)
+            {
+                client_set_queue (client, NULL);
+                client->check_buffer = format_check_file_buffer;
+            }
             avl_insert (dest->pending_tree, (void *)client);
+            count++;
         }
+        INFO2 ("passing %lu listeners to \"%s\"", count, dest->mount);
+
         source->listeners = 0;
         stats_event (source->mount, "listeners", "0");
         avl_tree_unlock (source->client_tree);
 
     } while (0);
 
+    /* see if we need to wake up an on-demand relay */
+    if (dest->running == 0 && dest->on_demand && count)
+    {
+        dest->on_demand_req = 1;
+        slave_rebuild_mounts();
+    }
+
     avl_tree_unlock (source->pending_tree);
     avl_tree_unlock (dest->pending_tree);
     thread_mutex_unlock (&move_clients_mutex);
@@ -695,6 +728,8 @@
         {
             INFO2("listener count on %s now %lu", source->mount, source->listeners);
             stats_event_args (source->mount, "listeners", "%lu", source->listeners);
+            if (source->listeners == 0 && source->on_demand)
+                source->running = 0;
         }
 
         /* lets reduce the queue, any lagging clients should of been
@@ -1051,6 +1086,14 @@
         DEBUG1 ("intro file is %s", mountinfo->intro_filename);
     if (source->dumpfilename)
         DEBUG1 ("Dumping stream to %s", source->dumpfilename);
+    if (source->on_demand)
+    {
+        DEBUG0 ("on_demand set");
+        stats_event (source->mount, "on_demand", "1");
+    }
+    else
+        stats_event (source->mount, "on_demand", NULL);
+
     if (source->hidden)
     {
         stats_event_hidden (source->mount, NULL, 1);

Modified: icecast/trunk/icecast/src/source.h
===================================================================
--- icecast/trunk/icecast/src/source.h	2005-06-09 01:39:48 UTC (rev 9405)
+++ icecast/trunk/icecast/src/source.h	2005-06-09 01:51:47 UTC (rev 9406)
@@ -68,6 +68,8 @@
     unsigned int queue_size_limit;
 
     unsigned timeout;  /* source timeout in seconds */
+    int on_demand;
+    int on_demand_req;
     int hidden;
     time_t last_read;
     int short_delay;



More information about the commits mailing list