Commit 2896db1f authored by Karl Heyes's avatar Karl Heyes

merge intro file implementation

svn path=/icecast/trunk/icecast/; revision=9345
parent 72ad63f7
......@@ -345,6 +345,7 @@ If you are relaying a Shoutcast stream, you need to specify this indicator to al
<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 @@ An optional value which will set the maximum number of listeners that can be att
<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
......
......@@ -190,6 +190,7 @@ void config_clear(ice_config_t *c)
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 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
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);
......
......@@ -46,6 +46,7 @@ typedef struct _mount_proxy {
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 */
......
......@@ -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_t *client_create(connection_t *con, http_parser_t *parser)
client->parser = parser;
client->refbuf = NULL;
client->pos = 0;
client->check_buffer = format_advance_queue;
return client;
}
......
......@@ -32,6 +32,9 @@ typedef struct _client_tag
/* 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 @@ typedef struct _client_tag
/* 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);
......
......@@ -952,6 +952,8 @@ static void _handle_get_request (client_t *client, char *passed_uri)
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);
......
......@@ -81,6 +81,130 @@ int format_get_plugin(format_type_t type, source_t *source)
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)
{
......
......@@ -61,14 +61,11 @@ format_type_t format_get_type(char *contenttype);
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__ */
......@@ -326,21 +326,8 @@ static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *clie
int ret, written = 0;
mp3_client_data *client_mp3 = client->format_data;
refbuf_t *refbuf = client->refbuf;
char *buf;
unsigned int len;
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;
char *buf = refbuf->data + client->pos;
unsigned int len = refbuf->len - client->pos;
do
{
......
......@@ -504,21 +504,11 @@ static int send_ogg_headers (client_t *client, refbuf_t *headers)
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)
......
......@@ -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 @@ void source_clear_source (source_t *source)
free(source->dumpfilename);
source->dumpfilename = NULL;
if (source->intro_file)
{
fclose (source->intro_file);
source->intro_file = NULL;
}
}
......@@ -344,7 +351,8 @@ void source_move_clients (source_t *source, source_t *dest)
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 @@ void source_move_clients (source_t *source, source_t *dest)
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 @@ void source_move_clients (source_t *source, source_t *dest)
}
/* 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 @@ static void send_to_listener (source_t *source, client_t *client, int deletion_e
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 @@ static void send_to_listener (source_t *source, client_t *client, int deletion_e
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 @@ static void send_to_listener (source_t *source, client_t *client, int deletion_e
/* 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 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo)
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 @@ void source_update_settings (ice_config_t *config, source_t *source, mount_proxy
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)
......
......@@ -46,6 +46,8 @@ typedef struct source_tag
rwlock_t *shutdown_rwlock;
util_dict *audio_info;
FILE *intro_file;
char *dumpfilename; /* Name of a file to dump incoming stream to */
FILE *dumpfile;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment