mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
merge intro file implementation
svn path=/icecast/trunk/icecast/; revision=9345
This commit is contained in:
parent
72ad63f763
commit
2896db1f3c
@ -345,6 +345,7 @@ If you are relaying a Shoutcast stream, you need to specify this indicator to al
|
|||||||
<password>hackmemore</password>
|
<password>hackmemore</password>
|
||||||
<max-listeners>1</max-listeners>
|
<max-listeners>1</max-listeners>
|
||||||
<dump-file>/tmp/dump-example1.ogg</dump-file>
|
<dump-file>/tmp/dump-example1.ogg</dump-file>
|
||||||
|
<intro>/intro.ogg</intro>
|
||||||
<fallback-mount>/example2.ogg</fallback-mount>
|
<fallback-mount>/example2.ogg</fallback-mount>
|
||||||
<fallback-override>1</fallback-override>
|
<fallback-override>1</fallback-override>
|
||||||
<public>1</public>
|
<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">
|
<div class="indentedbox">
|
||||||
An optional value which will set the filename which will be a dump of the stream coming through on this mountpoint.
|
An optional value which will set the filename which will be a dump of the stream coming through on this mountpoint.
|
||||||
</div>
|
</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>
|
<h4>fallback-mount</h4>
|
||||||
<div class="indentedbox">
|
<div class="indentedbox">
|
||||||
This optional value specifies a mountpoint that clients are automatically moved to if the source
|
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->username);
|
||||||
xmlFree(mount->password);
|
xmlFree(mount->password);
|
||||||
xmlFree(mount->dumpfile);
|
xmlFree(mount->dumpfile);
|
||||||
|
xmlFree(mount->intro_filename);
|
||||||
xmlFree(mount->fallback_mount);
|
xmlFree(mount->fallback_mount);
|
||||||
xmlFree(mount->stream_name);
|
xmlFree(mount->stream_name);
|
||||||
xmlFree(mount->stream_description);
|
xmlFree(mount->stream_description);
|
||||||
@ -558,6 +559,10 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
mount->dumpfile = (char *)xmlNodeListGetString(
|
mount->dumpfile = (char *)xmlNodeListGetString(
|
||||||
doc, node->xmlChildrenNode, 1);
|
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) {
|
else if (strcmp(node->name, "fallback-mount") == 0) {
|
||||||
mount->fallback_mount = (char *)xmlNodeListGetString(
|
mount->fallback_mount = (char *)xmlNodeListGetString(
|
||||||
doc, node->xmlChildrenNode, 1);
|
doc, node->xmlChildrenNode, 1);
|
||||||
|
@ -46,6 +46,7 @@ typedef struct _mount_proxy {
|
|||||||
|
|
||||||
char *dumpfile; /* Filename to dump this stream to (will be appended). NULL
|
char *dumpfile; /* Filename to dump this stream to (will be appended). NULL
|
||||||
to not dump. */
|
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
|
int max_listeners; /* Max listeners for this mountpoint only. -1 to not
|
||||||
limit here (i.e. only use the global limit) */
|
limit here (i.e. only use the global limit) */
|
||||||
char *fallback_mount; /* Fallback mountname */
|
char *fallback_mount; /* Fallback mountname */
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "cfgfile.h"
|
#include "cfgfile.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "refbuf.h"
|
#include "refbuf.h"
|
||||||
|
#include "format.h"
|
||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
@ -62,6 +63,7 @@ client_t *client_create(connection_t *con, http_parser_t *parser)
|
|||||||
client->parser = parser;
|
client->parser = parser;
|
||||||
client->refbuf = NULL;
|
client->refbuf = NULL;
|
||||||
client->pos = 0;
|
client->pos = 0;
|
||||||
|
client->check_buffer = format_advance_queue;
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@ typedef struct _client_tag
|
|||||||
/* http response code for this client */
|
/* http response code for this client */
|
||||||
int respcode;
|
int respcode;
|
||||||
|
|
||||||
|
/* is client getting intro data */
|
||||||
|
long intro_offset;
|
||||||
|
|
||||||
/* where in the queue the client is */
|
/* where in the queue the client is */
|
||||||
refbuf_t *refbuf;
|
refbuf_t *refbuf;
|
||||||
|
|
||||||
@ -46,6 +49,10 @@ typedef struct _client_tag
|
|||||||
|
|
||||||
/* function to call to release format specific resources */
|
/* function to call to release format specific resources */
|
||||||
void (*free_client_data)(struct _client_tag *client);
|
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_t *client_create(connection_t *con, http_parser_t *parser);
|
client_t *client_create(connection_t *con, http_parser_t *parser);
|
||||||
|
@ -953,6 +953,8 @@ static void _handle_get_request (client_t *client, char *passed_uri)
|
|||||||
sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
|
sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
|
||||||
sock_set_nodelay(client->con->sock);
|
sock_set_nodelay(client->con->sock);
|
||||||
|
|
||||||
|
client->check_buffer = format_check_file_buffer;
|
||||||
|
|
||||||
avl_tree_wlock(source->pending_tree);
|
avl_tree_wlock(source->pending_tree);
|
||||||
avl_insert(source->pending_tree, (void *)client);
|
avl_insert(source->pending_tree, (void *)client);
|
||||||
avl_tree_unlock(source->pending_tree);
|
avl_tree_unlock(source->pending_tree);
|
||||||
|
124
src/format.c
124
src/format.c
@ -81,6 +81,130 @@ int format_get_plugin(format_type_t type, source_t *source)
|
|||||||
return ret;
|
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,
|
void format_send_general_headers(format_plugin_t *format,
|
||||||
source_t *source, client_t *client)
|
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);
|
char *format_get_mimetype(format_type_t type);
|
||||||
int format_get_plugin(format_type_t type, struct source_tag *source);
|
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,
|
void format_send_general_headers(format_plugin_t *format,
|
||||||
struct source_tag *source, client_t *client);
|
struct source_tag *source, client_t *client);
|
||||||
|
|
||||||
#endif /* __FORMAT_H__ */
|
#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;
|
int ret, written = 0;
|
||||||
mp3_client_data *client_mp3 = client->format_data;
|
mp3_client_data *client_mp3 = client->format_data;
|
||||||
refbuf_t *refbuf = client->refbuf;
|
refbuf_t *refbuf = client->refbuf;
|
||||||
char *buf;
|
char *buf = refbuf->data + client->pos;
|
||||||
unsigned int len;
|
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
|
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)
|
static int write_buf_to_client (format_plugin_t *self, client_t *client)
|
||||||
{
|
{
|
||||||
refbuf_t *refbuf = client->refbuf;
|
refbuf_t *refbuf = client->refbuf;
|
||||||
char *buf;
|
char *buf = refbuf->data + client->pos;
|
||||||
unsigned len;
|
unsigned len = refbuf->len - client->pos;
|
||||||
struct ogg_client *client_data = client->format_data;
|
struct ogg_client *client_data = client->format_data;
|
||||||
int ret, written = 0;
|
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
|
do
|
||||||
{
|
{
|
||||||
if (client_data->headers != refbuf->associated)
|
if (client_data->headers != refbuf->associated)
|
||||||
|
65
src/source.c
65
src/source.c
@ -48,6 +48,7 @@
|
|||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
#undef CATMODULE
|
#undef CATMODULE
|
||||||
#define CATMODULE "source"
|
#define CATMODULE "source"
|
||||||
@ -250,6 +251,12 @@ void source_clear_source (source_t *source)
|
|||||||
|
|
||||||
free(source->dumpfilename);
|
free(source->dumpfilename);
|
||||||
source->dumpfilename = NULL;
|
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);
|
avl_delete (source->pending_tree, client, NULL);
|
||||||
|
|
||||||
/* switch client to different queue */
|
/* 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);
|
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);
|
avl_delete (source->client_tree, client, NULL);
|
||||||
|
|
||||||
/* switch client to different queue */
|
/* 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);
|
avl_insert (dest->pending_tree, (void *)client);
|
||||||
}
|
}
|
||||||
source->listeners = 0;
|
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
|
/* 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
|
* and sent back, however NULL is also valid as in the case of a short
|
||||||
* timeout and there's no data pending.
|
* 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 loop = 10; /* max number of iterations in one go */
|
||||||
int total_written = 0;
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
/* jump out if client connection has died */
|
/* 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--;
|
loop--;
|
||||||
|
|
||||||
|
if (client->check_buffer (source, client) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
bytes = source->format->write_buf_to_client (source->format, client);
|
bytes = source->format->write_buf_to_client (source->format, client);
|
||||||
if (bytes <= 0)
|
if (bytes <= 0)
|
||||||
break; /* can't write any more */
|
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
|
/* 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 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");
|
DEBUG0("Client has fallen too far behind, removing");
|
||||||
client->con->error = 1;
|
client->con->error = 1;
|
||||||
@ -1012,6 +997,24 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo)
|
|||||||
else
|
else
|
||||||
source->dumpfilename = NULL;
|
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)
|
if (mountinfo && mountinfo->queue_size_limit)
|
||||||
source->queue_size_limit = 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)
|
if (source->fallback_mount)
|
||||||
DEBUG1 ("fallback %s", 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)
|
if (source->dumpfilename)
|
||||||
DEBUG1 ("Dumping stream to %s", source->dumpfilename);
|
DEBUG1 ("Dumping stream to %s", source->dumpfilename);
|
||||||
if (source->hidden)
|
if (source->hidden)
|
||||||
|
@ -46,6 +46,8 @@ typedef struct source_tag
|
|||||||
rwlock_t *shutdown_rwlock;
|
rwlock_t *shutdown_rwlock;
|
||||||
util_dict *audio_info;
|
util_dict *audio_info;
|
||||||
|
|
||||||
|
FILE *intro_file;
|
||||||
|
|
||||||
char *dumpfilename; /* Name of a file to dump incoming stream to */
|
char *dumpfilename; /* Name of a file to dump incoming stream to */
|
||||||
FILE *dumpfile;
|
FILE *dumpfile;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user