[xiph-cvs] r6606 - in icecast/trunk/icecast: conf doc src

oddsock at xiph.org oddsock at xiph.org
Tue May 4 21:30:15 PDT 2004



Author: oddsock
Date: 2004-04-29 11:23:13 -0400 (Thu, 29 Apr 2004)
New Revision: 6606

Modified:
   icecast/trunk/icecast/conf/icecast.xml.in
   icecast/trunk/icecast/doc/icecast2_config_file.html
   icecast/trunk/icecast/src/cfgfile.c
   icecast/trunk/icecast/src/cfgfile.h
   icecast/trunk/icecast/src/client.c
   icecast/trunk/icecast/src/client.h
   icecast/trunk/icecast/src/format_vorbis.c
   icecast/trunk/icecast/src/refbuf.c
   icecast/trunk/icecast/src/refbuf.h
   icecast/trunk/icecast/src/source.c
   icecast/trunk/icecast/src/source.h
Log:
new feature in icecast : burst-on-connect - allows an initial burst of data to connecting listeners, thus reducing the startup time of a stream.

<p>Modified: icecast/trunk/icecast/conf/icecast.xml.in
===================================================================
--- icecast/trunk/icecast/conf/icecast.xml.in	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/conf/icecast.xml.in	2004-04-29 15:23:13 UTC (rev 6606)
@@ -7,6 +7,9 @@
         <client-timeout>30</client-timeout>
         <header-timeout>15</header-timeout>
         <source-timeout>10</source-timeout>
+        <!-- This will provide a burst of data when a client first connects,
+             thereby significantly reducing the startup time for a listener -->
+        <burst-on-connect>1</burst-on-connect>
     </limits>
 
     <authentication>

Modified: icecast/trunk/icecast/doc/icecast2_config_file.html
===================================================================
--- icecast/trunk/icecast/doc/icecast2_config_file.html	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/doc/icecast2_config_file.html	2004-04-29 15:23:13 UTC (rev 6606)
@@ -31,6 +31,7 @@
         &lt;client-timeout&gt;30&lt;client-timeout&gt;
         &lt;header-timeout&gt;15&lt;header-timeout&gt;
         &lt;source-timeout&gt;10&lt;source-timeout&gt;
+        &lt;burst-on-connect&gt;1&lt;burst-on-connect&gt;
     &lt;limits&gt;
 </pre>
 <p>This section contains server level settings that, in general, do not need to be changed.  Only modify this section if you are know what you are doing.
@@ -63,6 +64,10 @@
 <div class=indentedbox>
 If a connected source does not send any data within this timeout period (in seconds), then the source connection will be removed from the server.
 </div>
+<h4>burst-on-connect</h4>
+<div class=indentedbox>
+With this enabled, a connecting client will be sent a burst of audio data from the stream.  This will have the effect of reducing the startup time for the stream from the perspective of the listener.  This is due to the fact that most media players have local buffers that must be filled before the stream begins to play.  This may introduce a small latency in the stream (difference in time between when the source plays a clip and the listener hears a clip).  If this latency is important to you, then you can disable this feature.  The latency is bitrate-dependent, but as an example, for a 128kbps stream, the latency between the source and the player is ~ 1.5 secs WITHOUT burst on connect, and WITH burst on connect the latency is 3 secs.
+</div>
 <br>
 <br>
 <br>

Modified: icecast/trunk/icecast/src/cfgfile.c
===================================================================
--- icecast/trunk/icecast/src/cfgfile.c	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/cfgfile.c	2004-04-29 15:23:13 UTC (rev 6606)
@@ -339,6 +339,7 @@
     configuration->num_yp_directories = 0;
     configuration->relay_username = NULL;
     configuration->relay_password = NULL;
+    configuration->burst_on_connect = 1;
 }
 
 static void _parse_root(xmlDocPtr doc, xmlNodePtr node, 
@@ -460,6 +461,10 @@
             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
             configuration->source_timeout = atoi(tmp);
             if (tmp) xmlFree(tmp);
+        } else if (strcmp(node->name, "burst-on-connect") == 0) {
+            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+            configuration->burst_on_connect = atoi(tmp);
+            if (tmp) xmlFree(tmp);
         }
     } while ((node = node->next));
 }

Modified: icecast/trunk/icecast/src/cfgfile.h
===================================================================
--- icecast/trunk/icecast/src/cfgfile.h	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/cfgfile.h	2004-04-29 15:23:13 UTC (rev 6606)
@@ -133,6 +133,7 @@
     char *yp_url[MAX_YP_DIRECTORIES];
     int    yp_url_timeout[MAX_YP_DIRECTORIES];
     int num_yp_directories;
+    int burst_on_connect;
 } ice_config_t;
 
 typedef struct {

Modified: icecast/trunk/icecast/src/client.c
===================================================================
--- icecast/trunk/icecast/src/client.c	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/client.c	2004-04-29 15:23:13 UTC (rev 6606)
@@ -41,6 +41,7 @@
     client->parser = parser;
     client->queue = NULL;
     client->pos = 0;
+    client->burst_sent = 0;
 
     return client;
 }

Modified: icecast/trunk/icecast/src/client.h
===================================================================
--- icecast/trunk/icecast/src/client.h	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/client.h	2004-04-29 15:23:13 UTC (rev 6606)
@@ -45,6 +45,7 @@
 
     /* function to call to release format specific resources */
     void (*free_client_data)(struct _client_tag *client);
+    int burst_sent;
 } client_t;
 
 client_t *client_create(connection_t *con, http_parser_t *parser);

Modified: icecast/trunk/icecast/src/format_vorbis.c
===================================================================
--- icecast/trunk/icecast/src/format_vorbis.c	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/format_vorbis.c	2004-04-29 15:23:13 UTC (rev 6606)
@@ -119,10 +119,10 @@
     int i, result;
     ogg_packet op;
     char *tag;
-    refbuf_t *refbuf;
+    refbuf_t *refbuf, *source_refbuf;
     vstate_t *state = (vstate_t *)self->_state;
+    source_t *source;
 #ifdef USE_YP
-    source_t *source;
     time_t current_time;
 #endif
 
@@ -185,13 +185,24 @@
                 ogg_stream_clear(&state->os);
                 vorbis_comment_clear(&state->vc);
                 vorbis_info_clear(&state->vi);
-#ifdef USE_YP
-                /* If we get an update on the mountpoint, force a
-                   yp touch */
+
+                /* Drain the source queue on metadata update otherwise you
+                   could have a mismatch between what is on the source queue
+                   and what is in the state->headbuf */
                 avl_tree_rlock(global.source_tree);
                 source = source_find_mount_raw(self->mount);
                 avl_tree_unlock(global.source_tree);
 
+                thread_mutex_lock(&source->queue_mutex);
+                while ((source_refbuf = refbuf_queue_remove(&source->queue))) {
+                    refbuf_release(source_refbuf);
+                }
+                thread_mutex_unlock(&source->queue_mutex);
+
+#ifdef USE_YP
+                /* If we get an update on the mountpoint, force a
+                   yp touch */
+
                 if (source) {
                     /* If we get an update on the mountpoint, force a
                        yp touch */

Modified: icecast/trunk/icecast/src/refbuf.c
===================================================================
--- icecast/trunk/icecast/src/refbuf.c	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/refbuf.c	2004-04-29 15:23:13 UTC (rev 6606)
@@ -101,7 +101,21 @@
        
     return refbuf;
 }
+refbuf_t * refbuf_queue_get(refbuf_queue_t **queue, int item)
+{   
+    refbuf_queue_t *node = *queue;
+    int size = 0; 
+    while (node) {
+        if (size == item) {
+            return node->refbuf;
+        }
+        node = node->next; 
+        size++;
+    }
+    return NULL;
+}
 
+
 void refbuf_queue_insert(refbuf_queue_t **queue, refbuf_t *refbuf)
 {
     refbuf_queue_t *item = (refbuf_queue_t *)malloc(sizeof(refbuf_queue_t));

Modified: icecast/trunk/icecast/src/refbuf.h
===================================================================
--- icecast/trunk/icecast/src/refbuf.h	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/refbuf.h	2004-04-29 15:23:13 UTC (rev 6606)
@@ -49,6 +49,7 @@
 int refbuf_queue_size(refbuf_queue_t **queue);
 /* Size in bytes */
 int refbuf_queue_length(refbuf_queue_t **queue);
+refbuf_t * refbuf_queue_get(refbuf_queue_t **queue, int item);
 
 #endif  /* __REFBUF_H__ */
 

Modified: icecast/trunk/icecast/src/source.c
===================================================================
--- icecast/trunk/icecast/src/source.c	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/source.c	2004-04-29 15:23:13 UTC (rev 6606)
@@ -194,6 +194,7 @@
 
 void source_clear_source (source_t *source)
 {
+    refbuf_t *refbuf;
 #ifdef USE_YP
     int i;
 #endif
@@ -254,6 +255,12 @@
 
     free(source->dumpfilename);
     source->dumpfilename = NULL;
+    /* Lets clear out the source queue too */
+    while ((refbuf = refbuf_queue_remove(&source->queue)))
+        refbuf_release(refbuf);
+    source->queue = NULL;
+    source->burst_on_connect = 1;
+    thread_mutex_destroy(&source->queue_mutex);
 }
 
 
@@ -484,6 +491,7 @@
     memset (listenurl, '\000', listen_url_size);
     snprintf (listenurl, listen_url_size, "http://%s:%d%s",
             config->hostname, config->port, source->mount);
+    source->burst_on_connect = config->burst_on_connect;
     config_release_config();
 
     stats_event (source->mount, "listenurl", listenurl);
@@ -514,6 +522,8 @@
 
     sock_set_blocking (source->con->sock, SOCK_NONBLOCK);
 
+    thread_mutex_create(&source->queue_mutex);
+
     DEBUG0("Source creation complete");
     source->running = 1;
 
@@ -543,11 +553,11 @@
 {
     char buffer[4096];
     long bytes, sbytes;
-    int ret;
+    int ret, i;
     client_t *client;
     avl_node *client_node;
 
-    refbuf_t *refbuf, *abuf;
+    refbuf_t *refbuf, *abuf, *stale_refbuf;
     int data_done;
 
     source_init (source);
@@ -558,6 +568,27 @@
             WARN0("Bad data from source");
             break;
         }
+        if (source->burst_on_connect) {
+            thread_mutex_lock(&source->queue_mutex);
+            /* Add to the source buffer */
+            if (refbuf) {
+                refbuf_addref(refbuf);
+                refbuf_queue_add(&(source->queue), refbuf);
+                /* We derive the size of the source buffer queue based off the 
+                   setting for queue_size_limit (client buffer queue size).  
+                   This is because the source buffer queue size should be a
+                   percentage of the client buffer size (definately cannot
+                   be larger). Why 50% ? Because > 75% does not give the
+                   client enough leeway for lagging on initial connection
+                   and < 25% does not provide a good enough burst on connect. */
+                if (refbuf_queue_length(&(source->queue)) > 
+                    source->queue_size_limit/2) {
+                    stale_refbuf = refbuf_queue_remove(&(source->queue));
+                    refbuf_release(stale_refbuf);
+                }
+            }
+            thread_mutex_unlock(&source->queue_mutex);
+        }
         bytes = 1; /* Set to > 0 so that the post-loop check won't be tripped */
         while (refbuf == NULL) {
             bytes = 0;
@@ -590,6 +621,20 @@
                 WARN0("Bad data from source");
                 goto done;
             }
+            if (source->burst_on_connect) {
+                /* Add to the source buffer */
+                thread_mutex_lock(&source->queue_mutex);
+                if (refbuf) {
+                    refbuf_addref(refbuf);
+                    refbuf_queue_add(&(source->queue), refbuf);
+                    if (refbuf_queue_length(&(source->queue)) > 
+                        source->queue_size_limit/2) {
+                        stale_refbuf = refbuf_queue_remove(&(source->queue));
+                        refbuf_release(stale_refbuf);
+                    }
+                }
+                thread_mutex_unlock(&source->queue_mutex);
+            }
         }
 
         if (bytes <= 0) {
@@ -710,7 +755,10 @@
         /* release read lock on client_tree */
         avl_tree_unlock(source->client_tree);
 
-        refbuf_release(refbuf);
+        /* Only release the refbuf if we didn't add it to the source queue */
+        if (!source->burst_on_connect) {
+            refbuf_release(refbuf);
+        }
 
         /* acquire write lock on client_tree */
         avl_tree_wlock(source->client_tree);
@@ -767,10 +815,26 @@
             /* we have to send cached headers for some data formats
             ** this is where we queue up the buffers to send
             */
+            client = (client_t *)client_node->key;
             if (source->format->has_predata) {
-                client = (client_t *)client_node->key;
                 client->queue = source->format->get_predata(source->format);
             }
+            if (source->burst_on_connect) {
+                /* here is where we fill up the new client with refbufs from
+                   the source buffer.  this will allow an initial burst of
+                   audio data to be sent to the client, and allow for a faster
+                   startup time (from listener perspective) for the stream */ 
+                if (!client->burst_sent) {
+                    thread_mutex_lock(&source->queue_mutex);
+                    for (i=0;i<refbuf_queue_size(&(source->queue));i++) {
+                        refbuf_queue_add(&(client->queue),
+                            refbuf_queue_get(&(source->queue), i));
+                    }
+                    thread_mutex_unlock(&source->queue_mutex);
+                    client->burst_sent = 1;
+                    DEBUG1("Added %d buffers to initial client queue", refbuf_queue_length(&(source->queue)));
+                }
+            }
 
             client_node = avl_get_next(client_node);
         }

Modified: icecast/trunk/icecast/src/source.h
===================================================================
--- icecast/trunk/icecast/src/source.h	2004-04-29 08:24:48 UTC (rev 6605)
+++ icecast/trunk/icecast/src/source.h	2004-04-29 15:23:13 UTC (rev 6606)
@@ -58,6 +58,9 @@
     int no_mount;
     unsigned queue_size_limit;
     unsigned timeout;  /* source timeout in seconds */
+    refbuf_queue_t *queue;
+    mutex_t queue_mutex;
+    int burst_on_connect;
 } source_t;
 
 source_t *source_reserve (const char *mount);

--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list