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

karl at motherfish-iii.xiph.org karl at motherfish-iii.xiph.org
Fri Jun 3 08:36:01 PDT 2005


Author: karl
Date: 2005-06-03 08:35:52 -0700 (Fri, 03 Jun 2005)
New Revision: 9345

Modified:
   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/connection.c
   icecast/trunk/icecast/src/format.c
   icecast/trunk/icecast/src/format.h
   icecast/trunk/icecast/src/format_mp3.c
   icecast/trunk/icecast/src/format_ogg.c
   icecast/trunk/icecast/src/source.c
   icecast/trunk/icecast/src/source.h
Log:
merge intro file implementation


Modified: icecast/trunk/icecast/doc/icecast2_config_file.html
===================================================================
--- icecast/trunk/icecast/doc/icecast2_config_file.html	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/doc/icecast2_config_file.html	2005-06-03 15:35:52 UTC (rev 9345)
@@ -345,6 +345,7 @@
         <password>hackmemore</password>
         <max-listeners>1</max-listeners>
         <dump-file>/tmp/dump-example1.ogg</dump-file>
+        <intro>/intro.ogg</intro>
         <fallback-mount>/example2.ogg</fallback-mount>
         <fallback-override>1</fallback-override>
         <public>1</public>
@@ -396,6 +397,15 @@
 <div class="indentedbox">
 An optional value which will set the filename which will be a dump of the stream coming through on this mountpoint.
 </div>
+<h4>intro</h4>
+<div class="indentedbox">
+    <p>An optional value which will specify the file those contents will be sent to new listeners
+    when they connect but before the normal stream is sent. Make sure the format of the file
+    specified matches the streaming format.  The specified file is appended to webroot before
+    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

Modified: icecast/trunk/icecast/src/cfgfile.c
===================================================================
--- icecast/trunk/icecast/src/cfgfile.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/cfgfile.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -190,6 +190,7 @@
         xmlFree(mount->username);
         xmlFree(mount->password);
         xmlFree(mount->dumpfile);
+        xmlFree(mount->intro_filename);
         xmlFree(mount->fallback_mount);
         xmlFree(mount->stream_name);
         xmlFree(mount->stream_description);
@@ -558,6 +559,10 @@
             mount->dumpfile = (char *)xmlNodeListGetString(
                     doc, node->xmlChildrenNode, 1);
         }
+        else if (strcmp(node->name, "intro") == 0) {
+            mount->intro_filename = (char *)xmlNodeListGetString(
+                    doc, node->xmlChildrenNode, 1);
+        }
         else if (strcmp(node->name, "fallback-mount") == 0) {
             mount->fallback_mount = (char *)xmlNodeListGetString(
                     doc, node->xmlChildrenNode, 1);

Modified: icecast/trunk/icecast/src/cfgfile.h
===================================================================
--- icecast/trunk/icecast/src/cfgfile.h	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/cfgfile.h	2005-06-03 15:35:52 UTC (rev 9345)
@@ -46,6 +46,7 @@
 
     char *dumpfile; /* Filename to dump this stream to (will be appended). NULL
                        to not dump. */
+    char *intro_filename;   /* Send contents of file to client before the stream */
     int max_listeners; /* Max listeners for this mountpoint only. -1 to not 
                           limit here (i.e. only use the global limit) */
     char *fallback_mount; /* Fallback mountname */

Modified: icecast/trunk/icecast/src/client.c
===================================================================
--- icecast/trunk/icecast/src/client.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/client.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -30,6 +30,7 @@
 #include "cfgfile.h"
 #include "connection.h"
 #include "refbuf.h"
+#include "format.h"
 #include "stats.h"
 
 #include "client.h"
@@ -62,6 +63,7 @@
     client->parser = parser;
     client->refbuf = NULL;
     client->pos = 0;
+    client->check_buffer = format_advance_queue;
 
     return client;
 }

Modified: icecast/trunk/icecast/src/client.h
===================================================================
--- icecast/trunk/icecast/src/client.h	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/client.h	2005-06-03 15:35:52 UTC (rev 9345)
@@ -32,6 +32,9 @@
     /* http response code for this client */
     int respcode;
 
+     /* is client getting intro data */
+     long intro_offset;
+
     /* where in the queue the client is */
     refbuf_t *refbuf;
 
@@ -46,6 +49,10 @@
 
     /* function to call to release format specific resources */
     void (*free_client_data)(struct _client_tag *client);
+
+    /* function to check if refbuf needs updating */
+    int (*check_buffer)(struct source_tag *source, struct _client_tag *client);
+
 } client_t;
 
 client_t *client_create(connection_t *con, http_parser_t *parser);

Modified: icecast/trunk/icecast/src/connection.c
===================================================================
--- icecast/trunk/icecast/src/connection.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/connection.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -952,6 +952,8 @@
                             
         sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
         sock_set_nodelay(client->con->sock);
+
+        client->check_buffer = format_check_file_buffer;
                         
         avl_tree_wlock(source->pending_tree);
         avl_insert(source->pending_tree, (void *)client);

Modified: icecast/trunk/icecast/src/format.c
===================================================================
--- icecast/trunk/icecast/src/format.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/format.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -81,6 +81,130 @@
     return ret;
 }
 
+
+/* clients need to be start from somewhere in the queue so we will look for
+ * a refbuf which has been previously marked as a sync point. 
+ */
+static void find_client_start (source_t *source, client_t *client)
+{
+    refbuf_t *refbuf = source->burst_point;
+
+    /* we only want to attempt a burst at connection time, not midstream */
+    if (client->intro_offset == -1)
+        refbuf = source->stream_data_tail;
+    else
+    {
+        long size = 0;
+        refbuf = source->burst_point;
+        size = source->burst_size - client->intro_offset;
+        while (size > 0 && refbuf->next)
+        {
+            size -= refbuf->len;
+            refbuf = refbuf->next;
+        }
+    }
+
+    while (refbuf)
+    {
+        if (refbuf->sync_point)
+        {
+            client_set_queue (client, refbuf);
+            client->check_buffer = format_advance_queue;
+            client->intro_offset = -1;
+            break;
+        }
+        refbuf = refbuf->next;
+    }
+}
+
+
+static int get_file_data (FILE *intro, client_t *client)
+{
+    refbuf_t *refbuf = client->refbuf;
+    int bytes;
+
+    if (intro == NULL || fseek (intro, client->intro_offset, SEEK_SET) < 0)
+        return 0;
+    bytes = fread (refbuf->data, 1, 4096, intro);
+    if (bytes == 0)
+        return 0;
+
+    refbuf->len = bytes;
+    return 1;
+}
+
+
+/* call to check the buffer contents for file reading. move the client
+ * to right place in the queue at end of file else repeat file if queue
+ * is not ready yet.
+ */
+int format_check_file_buffer (source_t *source, client_t *client)
+{
+    refbuf_t *refbuf = client->refbuf;
+
+    if (refbuf == NULL)
+    {
+        if (source->intro_file && client->intro_offset == 0)
+        {
+            refbuf = refbuf_new (4096);
+            client->refbuf = refbuf;
+            client->pos = refbuf->len;
+        }
+        else
+        {
+            find_client_start (source, client);
+            return -1;
+        }
+    }
+    if (client->pos == refbuf->len)
+    {
+        if (get_file_data (source->intro_file, client))
+        {
+            client->pos = 0;
+            client->intro_offset += refbuf->len;
+        }
+        else
+        {
+            if (source->stream_data_tail)
+            {
+                /* better find the right place in queue for this client */
+                client->intro_offset = -1;
+                client_set_queue (client, NULL);
+                find_client_start (source, client);
+            }
+            else
+                client->intro_offset = 0;  /* replay intro file */
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+/* This is the commonly used for source streams, here we just progress to
+ * the next buffer in the queue if there is no more left to be written from 
+ * the existing buffer.
+ */
+int format_advance_queue (source_t *source, client_t *client)
+{
+    refbuf_t *refbuf = client->refbuf;
+
+    if (refbuf == NULL)
+        return -1;
+
+    if (refbuf->next == NULL && client->pos == refbuf->len)
+        return -1;
+
+    /* move to the next buffer if we have finished with the current one */
+    if (refbuf->next && client->pos == refbuf->len)
+    {
+        client_set_queue (client, refbuf->next);
+        refbuf = client->refbuf;
+    }
+    return 0;
+}
+
+
 void format_send_general_headers(format_plugin_t *format,
         source_t *source, client_t *client)
 {

Modified: icecast/trunk/icecast/src/format.h
===================================================================
--- icecast/trunk/icecast/src/format.h	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/format.h	2005-06-03 15:35:52 UTC (rev 9345)
@@ -61,14 +61,11 @@
 char *format_get_mimetype(format_type_t type);
 int format_get_plugin(format_type_t type, struct source_tag *source);
 
+int format_advance_queue (struct source_tag *source, client_t *client);
+int format_check_file_buffer (struct source_tag *source, client_t *client);
+
 void format_send_general_headers(format_plugin_t *format, 
         struct source_tag *source, client_t *client);
 
 #endif  /* __FORMAT_H__ */
 
-
-
-
-
-
-

Modified: icecast/trunk/icecast/src/format_mp3.c
===================================================================
--- icecast/trunk/icecast/src/format_mp3.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/format_mp3.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -326,22 +326,9 @@
     int ret, written = 0;
     mp3_client_data *client_mp3 = client->format_data;
     refbuf_t *refbuf = client->refbuf;
-    char *buf;
-    unsigned int len;
+    char *buf = refbuf->data + client->pos;
+    unsigned int len = refbuf->len - client->pos;
 
-    if (refbuf->next == NULL && client->pos == refbuf->len)
-        return 0;
-
-    /* move to the next buffer if we have finished with the current one */
-    if (refbuf->next && client->pos == refbuf->len)
-    {
-        client_set_queue (client, refbuf->next);
-        refbuf = client->refbuf;
-    }
-
-    buf = refbuf->data + client->pos;
-    len = refbuf->len - client->pos;
-
     do
     {
         /* send any unwritten metadata to the client */

Modified: icecast/trunk/icecast/src/format_ogg.c
===================================================================
--- icecast/trunk/icecast/src/format_ogg.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/format_ogg.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -504,21 +504,11 @@
 static int write_buf_to_client (format_plugin_t *self, client_t *client)
 {
     refbuf_t *refbuf = client->refbuf;
-    char *buf;
-    unsigned len;
+    char *buf = refbuf->data + client->pos;
+    unsigned len = refbuf->len - client->pos;
     struct ogg_client *client_data = client->format_data;
     int ret, written = 0;
 
-    if (refbuf->next == NULL && client->pos == refbuf->len)
-        return 0;
-
-    if (refbuf->next && client->pos == refbuf->len)
-    {
-        client_set_queue (client, refbuf->next);
-        refbuf = client->refbuf;
-    }
-    buf = refbuf->data + client->pos;
-    len = refbuf->len - client->pos;
     do
     {
         if (client_data->headers != refbuf->associated)

Modified: icecast/trunk/icecast/src/source.c
===================================================================
--- icecast/trunk/icecast/src/source.c	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/source.c	2005-06-03 15:35:52 UTC (rev 9345)
@@ -48,6 +48,7 @@
 #include "source.h"
 #include "format.h"
 #include "auth.h"
+#include "os.h"
 
 #undef CATMODULE
 #define CATMODULE "source"
@@ -250,6 +251,12 @@
 
     free(source->dumpfilename);
     source->dumpfilename = NULL;
+
+    if (source->intro_file)
+    {
+        fclose (source->intro_file);
+        source->intro_file = NULL;
+    }
 }
 
 
@@ -344,7 +351,8 @@
             avl_delete (source->pending_tree, client, NULL);
 
             /* switch client to different queue */
-            client_set_queue (client, dest->stream_data_tail);
+            client_set_queue (client, NULL);
+            client->check_buffer = format_check_file_buffer;
             avl_insert (dest->pending_tree, (void *)client);
         }
 
@@ -359,7 +367,8 @@
             avl_delete (source->client_tree, client, NULL);
 
             /* switch client to different queue */
-            client_set_queue (client, dest->stream_data_tail);
+            client_set_queue (client, NULL);
+            client->check_buffer = format_check_file_buffer;
             avl_insert (dest->pending_tree, (void *)client);
         }
         source->listeners = 0;
@@ -374,25 +383,6 @@
 }
 
 
-/* clients need to be start from somewhere in the queue
- * so we will look for a refbuf which has been previous
- * marked as a sync point */
-static void find_client_start (source_t *source, client_t *client)
-{
-    refbuf_t *refbuf = source->burst_point;
-
-    while (refbuf)
-    {
-        if (refbuf->sync_point)
-        {
-            client_set_queue (client, refbuf);
-            break;
-        }
-        refbuf = refbuf->next;
-    }
-}
-
-
 /* get some data from the source. The stream data is placed in a refbuf
  * and sent back, however NULL is also valid as in the case of a short
  * timeout and there's no data pending.
@@ -466,14 +456,6 @@
     int loop = 10;   /* max number of iterations in one go */
     int total_written = 0;
 
-    /* new users need somewhere to start from */
-    if (client->refbuf == NULL)
-    {
-        find_client_start (source, client);
-        if (client->refbuf == NULL)
-            return;
-    }
-
     while (1)
     {
         /* jump out if client connection has died */
@@ -490,6 +472,9 @@
 
         loop--;
 
+        if (client->check_buffer (source, client) < 0)
+            break;
+
         bytes = source->format->write_buf_to_client (source->format, client);
         if (bytes <= 0)
             break;  /* can't write any more */
@@ -500,7 +485,7 @@
 
     /* the refbuf referenced at head (last in queue) may be marked for deletion
      * if so, check to see if this client is still referring to it */
-    if (deletion_expected && client->refbuf == source->stream_data)
+    if (deletion_expected && client->refbuf && client->refbuf == source->stream_data)
     {
         DEBUG0("Client has fallen too far behind, removing");
         client->con->error = 1;
@@ -1012,6 +997,24 @@
     else
         source->dumpfilename = NULL;
 
+    if (mountinfo && mountinfo->intro_filename && source->intro_file == NULL)
+    {
+        ice_config_t *config = config_get_config_unlocked ();
+        unsigned int len  = strlen (config->webroot_dir) +
+            strlen (mountinfo->intro_filename) + 2;
+        char *path = malloc (len);
+        if (path)
+        {
+            snprintf (path, len, "%s" PATH_SEPARATOR "%s", config->webroot_dir,
+                    mountinfo->intro_filename);
+
+            source->intro_file = fopen (path, "rb");
+            if (source->intro_file == NULL)
+                WARN2 ("Cannot open intro file \"%s\": %s", path, strerror(errno));
+            free (path);
+        }
+    }
+
     if (mountinfo && mountinfo->queue_size_limit)
         source->queue_size_limit = mountinfo->queue_size_limit;
 
@@ -1040,6 +1043,8 @@
 
     if (source->fallback_mount)
         DEBUG1 ("fallback %s", source->fallback_mount);
+    if (mountinfo && mountinfo->intro_filename)
+        DEBUG1 ("intro file is %s", mountinfo->intro_filename);
     if (source->dumpfilename)
         DEBUG1 ("Dumping stream to %s", source->dumpfilename);
     if (source->hidden)

Modified: icecast/trunk/icecast/src/source.h
===================================================================
--- icecast/trunk/icecast/src/source.h	2005-06-03 11:06:04 UTC (rev 9344)
+++ icecast/trunk/icecast/src/source.h	2005-06-03 15:35:52 UTC (rev 9345)
@@ -46,6 +46,8 @@
     rwlock_t *shutdown_rwlock;
     util_dict *audio_info;
 
+    FILE *intro_file;
+
     char *dumpfilename; /* Name of a file to dump incoming stream to */
     FILE *dumpfile;
 



More information about the commits mailing list