mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-11-03 04:17:17 -05:00
various updates, some cleanups, fixup some mp3 metadata via url problems
make re-sync to trunk easier svn path=/icecast/branches/kh/icecast/; revision=7176
This commit is contained in:
parent
47dd068dee
commit
5fae00fb71
102
src/format_mp3.c
102
src/format_mp3.c
@ -95,7 +95,6 @@ int format_mp3_get_plugin (source_t *source)
|
||||
|
||||
meta = refbuf_new (1);
|
||||
memcpy (meta->data, "", 1);
|
||||
meta->len = 1;
|
||||
state->metadata = meta;
|
||||
state->interval = ICY_METADATA_INTERVAL;
|
||||
|
||||
@ -135,18 +134,17 @@ static void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value)
|
||||
source_mp3->url_title = p;
|
||||
source_mp3->update_metadata = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (strcmp (tag, "artist") == 0)
|
||||
else if (strcmp (tag, "artist") == 0)
|
||||
{
|
||||
char *p = strdup (value);
|
||||
if (p)
|
||||
{
|
||||
free (source_mp3->url_artist);
|
||||
source_mp3->url_artist = p;
|
||||
source_mp3->update_metadata = 1;
|
||||
}
|
||||
}
|
||||
source_mp3->update_metadata = 1;
|
||||
}
|
||||
|
||||
|
||||
@ -178,15 +176,19 @@ static void filter_shoutcast_metadata (source_t *source, char *metadata, unsigne
|
||||
}
|
||||
|
||||
|
||||
void mp3_set_title (source_t *source)
|
||||
/* called from the source thread when the metadata has been updated.
|
||||
* The artist title are checked and made ready for clients to send
|
||||
*/
|
||||
static void mp3_set_title (source_t *source)
|
||||
{
|
||||
const char meta[] = "StreamTitle='";
|
||||
int size;
|
||||
unsigned char len_byte;
|
||||
refbuf_t *p;
|
||||
unsigned len = sizeof(meta) + 6;
|
||||
unsigned len = sizeof(meta) + 2; /* the StreamTitle, quotes, ; and null */
|
||||
mp3_state *source_mp3 = source->format->_state;
|
||||
|
||||
/* work out message length */
|
||||
if (source_mp3->url_artist)
|
||||
len += strlen (source_mp3->url_artist);
|
||||
if (source_mp3->url_title)
|
||||
@ -194,16 +196,18 @@ void mp3_set_title (source_t *source)
|
||||
if (source_mp3->url_artist && source_mp3->url_title)
|
||||
len += 3;
|
||||
#define MAX_META_LEN 255*16
|
||||
size = sizeof (meta) + len + 2;
|
||||
if (len > MAX_META_LEN-(sizeof(meta)+3))
|
||||
if (len > MAX_META_LEN)
|
||||
{
|
||||
WARN1 ("Metadata too long at %d chars", len);
|
||||
return;
|
||||
}
|
||||
len_byte = size / 16 + 1;
|
||||
/* work out the metadata len byte */
|
||||
len_byte = (len-1) / 16 + 1;
|
||||
|
||||
/* now we know how much space to allocate, +1 for the len byte */
|
||||
size = len_byte * 16 + 1;
|
||||
|
||||
p = refbuf_new (size);
|
||||
p->len = size;
|
||||
if (p)
|
||||
{
|
||||
mp3_state *source_mp3 = source->format->_state;
|
||||
@ -213,13 +217,20 @@ void mp3_set_title (source_t *source)
|
||||
snprintf (p->data, size, "%c%s%s - %s';", len_byte, meta,
|
||||
source_mp3->url_artist, source_mp3->url_title);
|
||||
else
|
||||
snprintf (p->data, size, "%c%s%.*s';", len_byte, meta, len, source_mp3->url_title);
|
||||
snprintf (p->data, size, "%c%s%s';", len_byte, meta,
|
||||
source_mp3->url_title);
|
||||
filter_shoutcast_metadata (source, p->data, size);
|
||||
|
||||
refbuf_release (source_mp3->metadata);
|
||||
source_mp3->metadata = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* send the appropriate metadata, and return the number of bytes written
|
||||
* which is 0 or greater. Check the client in_metadata value afterwards
|
||||
* to see if all metadata has been sent
|
||||
*/
|
||||
static int send_mp3_metadata (client_t *client, refbuf_t *associated)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -227,6 +238,9 @@ static int send_mp3_metadata (client_t *client, refbuf_t *associated)
|
||||
int meta_len;
|
||||
mp3_client_data *client_mp3 = client->format_data;
|
||||
|
||||
/* If there is a change in metadata then send it else
|
||||
* send a single zero value byte in its place
|
||||
*/
|
||||
if (associated == client_mp3->associated)
|
||||
{
|
||||
metadata = "\0";
|
||||
@ -249,14 +263,17 @@ static int send_mp3_metadata (client_t *client, refbuf_t *associated)
|
||||
}
|
||||
if (ret > 0)
|
||||
client_mp3->metadata_offset += ret;
|
||||
else
|
||||
ret = 0;
|
||||
client_mp3->in_metadata = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* return bytes actually written, -1 for error or 0 for no more data to write */
|
||||
|
||||
/* Handler for writing mp3 data to a client, taking into account whether
|
||||
* client has requested shoutcast style metadata updates
|
||||
*/
|
||||
static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *client)
|
||||
{
|
||||
int ret, written = 0;
|
||||
@ -281,14 +298,15 @@ static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *clie
|
||||
refbuf_t *associated = refbuf->associated;
|
||||
ret = send_mp3_metadata (client, associated);
|
||||
|
||||
if (ret < (int)associated->len)
|
||||
if (client_mp3->in_metadata)
|
||||
break;
|
||||
written += ret;
|
||||
}
|
||||
/* see if we need to send the current metadata to the client */
|
||||
if (client_mp3->use_metadata)
|
||||
{
|
||||
unsigned remaining = source_mp3->interval - client_mp3->since_meta_block;
|
||||
unsigned remaining = source_mp3->interval -
|
||||
client_mp3->since_meta_block;
|
||||
|
||||
/* sending the metadata block */
|
||||
if (remaining <= len)
|
||||
@ -331,7 +349,7 @@ static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *clie
|
||||
written += ret;
|
||||
}
|
||||
ret = 0;
|
||||
/* we have now written what we need to in here */
|
||||
/* we have now written what we needed to so move to the next buffer */
|
||||
if (refbuf->next)
|
||||
{
|
||||
client->refbuf = refbuf->next;
|
||||
@ -341,28 +359,32 @@ static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *clie
|
||||
|
||||
if (ret > 0)
|
||||
written += ret;
|
||||
return written ? written : -1;
|
||||
return written;
|
||||
}
|
||||
|
||||
static void format_mp3_free_plugin (format_plugin_t *plugin)
|
||||
{
|
||||
/* free the plugin instance */
|
||||
mp3_state *state = plugin->_state;
|
||||
mp3_state *format_mp3 = plugin->_state;
|
||||
|
||||
free(state);
|
||||
free (format_mp3->url_artist);
|
||||
free (format_mp3->url_title);
|
||||
refbuf_release (format_mp3->metadata);
|
||||
free(format_mp3);
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
|
||||
/* read an mp3 stream which does not have shoutcast style metadata */
|
||||
static refbuf_t *mp3_get_no_meta (source_t *source)
|
||||
{
|
||||
int bytes;
|
||||
refbuf_t *refbuf;
|
||||
mp3_state *source_mp3 = source->format->_state;
|
||||
|
||||
if ((refbuf = refbuf_new (4096)) == NULL)
|
||||
if ((refbuf = refbuf_new (2048)) == NULL)
|
||||
return NULL;
|
||||
bytes = sock_read_bytes (source->con->sock, refbuf->data, 4096);
|
||||
bytes = sock_read_bytes (source->con->sock, refbuf->data, 2048);
|
||||
|
||||
if (bytes == 0)
|
||||
{
|
||||
@ -380,6 +402,7 @@ static refbuf_t *mp3_get_no_meta (source_t *source)
|
||||
{
|
||||
refbuf->len = bytes;
|
||||
refbuf->associated = source_mp3->metadata;
|
||||
refbuf_addref (source_mp3->metadata);
|
||||
refbuf->sync_point = 1;
|
||||
return refbuf;
|
||||
}
|
||||
@ -392,6 +415,10 @@ static refbuf_t *mp3_get_no_meta (source_t *source)
|
||||
}
|
||||
|
||||
|
||||
/* read mp3 data with inlined metadata from the source. Filter out the
|
||||
* metadata so that the mp3 data itself is store on the queue and the
|
||||
* metadata is is associated with it
|
||||
*/
|
||||
static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
{
|
||||
refbuf_t *refbuf;
|
||||
@ -428,10 +455,11 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
return NULL;
|
||||
}
|
||||
/* fill the buffer with the read data */
|
||||
bytes = (unsigned)ret;
|
||||
bytes = (unsigned int)ret;
|
||||
refbuf->len = 0;
|
||||
while (bytes > 0)
|
||||
{
|
||||
unsigned metadata_remaining;
|
||||
unsigned int metadata_remaining;
|
||||
|
||||
mp3_block = source_mp3->inline_metadata_interval - source_mp3->offset;
|
||||
|
||||
@ -442,7 +470,8 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
source_mp3->offset += bytes;
|
||||
break;
|
||||
}
|
||||
/* we have enough data to get to the metadata block, but only transfer upto it */
|
||||
/* we have enough data to get to the metadata
|
||||
* block, but only transfer upto it */
|
||||
if (mp3_block)
|
||||
{
|
||||
src += mp3_block;
|
||||
@ -452,25 +481,29 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* are we processing the inline metadata, len == 0 indicates not seen any */
|
||||
/* process the inline metadata, len == 0 indicates not seen any yet */
|
||||
if (source_mp3->build_metadata_len == 0)
|
||||
{
|
||||
memset (source_mp3->build_metadata, 0, sizeof (source_mp3->build_metadata));
|
||||
memset (source_mp3->build_metadata, 0,
|
||||
sizeof (source_mp3->build_metadata));
|
||||
source_mp3->build_metadata_offset = 0;
|
||||
source_mp3->build_metadata_len = 1 + (*src * 16);
|
||||
}
|
||||
|
||||
/* do we have all of the metatdata block */
|
||||
metadata_remaining = source_mp3->build_metadata_len - source_mp3->build_metadata_offset;
|
||||
metadata_remaining = source_mp3->build_metadata_len -
|
||||
source_mp3->build_metadata_offset;
|
||||
if (bytes < metadata_remaining)
|
||||
{
|
||||
memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset,
|
||||
src, bytes);
|
||||
memcpy (source_mp3->build_metadata +
|
||||
source_mp3->build_metadata_offset, src, bytes);
|
||||
source_mp3->build_metadata_offset += bytes;
|
||||
break;
|
||||
}
|
||||
/* copy all bytes except the last one, that way we *
|
||||
* know a null byte terminates the message */
|
||||
memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset,
|
||||
src, metadata_remaining);
|
||||
src, metadata_remaining-1);
|
||||
|
||||
/* overwrite metadata in the buffer */
|
||||
bytes -= metadata_remaining;
|
||||
@ -480,13 +513,15 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
if (source_mp3->build_metadata_len > 1)
|
||||
{
|
||||
refbuf_t *meta = refbuf_new (source_mp3->build_metadata_len);
|
||||
memcpy (meta->data, source_mp3->build_metadata, source_mp3->build_metadata_len);
|
||||
meta->len = source_mp3->build_metadata_len;
|
||||
memcpy (meta->data, source_mp3->build_metadata,
|
||||
source_mp3->build_metadata_len);
|
||||
|
||||
DEBUG1("shoutcast metadata %.4080s", meta->data+1);
|
||||
if (strncmp (meta->data+1, "StreamTitle=", 12) == 0)
|
||||
{
|
||||
filter_shoutcast_metadata (source, source_mp3->build_metadata, source_mp3->build_metadata_len);
|
||||
filter_shoutcast_metadata (source, source_mp3->build_metadata,
|
||||
source_mp3->build_metadata_len);
|
||||
refbuf_release (source_mp3->metadata);
|
||||
source_mp3->metadata = meta;
|
||||
}
|
||||
else
|
||||
@ -501,6 +536,7 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
source_mp3->build_metadata_len = 0;
|
||||
}
|
||||
refbuf->associated = source_mp3->metadata;
|
||||
refbuf_addref (source_mp3->metadata);
|
||||
refbuf->sync_point = 1;
|
||||
|
||||
return refbuf;
|
||||
|
@ -105,10 +105,8 @@ static refbuf_t *make_refbuf_with_page (ogg_page *page)
|
||||
{
|
||||
refbuf_t *refbuf = refbuf_new (page->header_len + page->body_len);
|
||||
|
||||
refbuf->idx = ogg_page_pageno (page);
|
||||
memcpy (refbuf->data, page->header, page->header_len);
|
||||
memcpy (refbuf->data+page->header_len, page->body, page->body_len);
|
||||
refbuf->len = page->header_len + page->body_len;
|
||||
return refbuf;
|
||||
}
|
||||
|
||||
@ -365,7 +363,6 @@ static refbuf_t *process_theora_page (ogg_codec_t *codec, ogg_page *page)
|
||||
return NULL;
|
||||
}
|
||||
refbuf = make_refbuf_with_page (page);
|
||||
refbuf->idx = ogg_page_pageno (page);
|
||||
|
||||
// DEBUG2 ("granulepos is %lld, %p", granulepos, refbuf);
|
||||
if (granulepos == -1 || granulepos == theora->prev_granulepos)
|
||||
@ -446,9 +443,22 @@ static int write_buf_to_client (format_plugin_t *self, client_t *client);
|
||||
static void free_ogg_codecs (ogg_state_t *ogg_info)
|
||||
{
|
||||
ogg_codec_t *codec;
|
||||
refbuf_t *header;
|
||||
|
||||
if (ogg_info == NULL)
|
||||
return;
|
||||
/* release the header pages first */
|
||||
header = ogg_info->header_pages;
|
||||
while (header)
|
||||
{
|
||||
refbuf_t *to_release = header;
|
||||
header = header->next;
|
||||
refbuf_release (to_release);
|
||||
}
|
||||
ogg_info->header_pages = NULL;
|
||||
ogg_info->header_pages_tail = NULL;
|
||||
|
||||
/* now free the codecs */
|
||||
codec = ogg_info->codecs;
|
||||
while (codec)
|
||||
{
|
||||
@ -515,8 +525,6 @@ static int process_initial_page (ogg_state_t *ogg_info, ogg_page *page)
|
||||
ogg_info->codec_sync = NULL;
|
||||
/* need to zap old list of codecs when next group of BOS pages appear */
|
||||
free_ogg_codecs (ogg_info);
|
||||
ogg_info->header_pages = NULL;
|
||||
ogg_info->header_pages_tail = NULL;
|
||||
}
|
||||
do
|
||||
{
|
||||
@ -567,7 +575,15 @@ static refbuf_t *process_ogg_page (ogg_state_t *ogg_info, ogg_page *page)
|
||||
{
|
||||
refbuf_t *refbuf = codec->process_page (codec, page);
|
||||
if (refbuf)
|
||||
{
|
||||
refbuf_t *header = ogg_info->header_pages;
|
||||
while (header)
|
||||
{
|
||||
refbuf_addref (header);
|
||||
header = header->next;
|
||||
}
|
||||
refbuf->associated = ogg_info->header_pages;
|
||||
}
|
||||
return refbuf;
|
||||
}
|
||||
codec = codec->next;
|
||||
@ -758,7 +774,7 @@ static int write_buf_to_client (format_plugin_t *self, client_t *client)
|
||||
|
||||
if (ret > 0)
|
||||
written += ret;
|
||||
return written ? written : -1;
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
|
@ -226,6 +226,7 @@ static refbuf_t *get_buffer_audio (vstate_t *source_vorbis)
|
||||
}
|
||||
if (get_ogg_page (&source_vorbis->out_os, &page) > 0)
|
||||
{
|
||||
refbuf *header;
|
||||
/* printf ("got audio page %lld\n", ogg_page_granulepos (&page)); */
|
||||
/* squeeze a page copy into a buffer */
|
||||
source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
|
||||
@ -234,8 +235,13 @@ static refbuf_t *get_buffer_audio (vstate_t *source_vorbis)
|
||||
refbuf = refbuf_new (page.header_len + page.body_len);
|
||||
memcpy (refbuf->data, page.header, page.header_len);
|
||||
memcpy (refbuf->data+page.header_len, page.body, page.body_len);
|
||||
refbuf->len = page.header_len + page.body_len;
|
||||
refbuf->associated = source_vorbis->headers_head;
|
||||
header = source_vorbis->headers_head;
|
||||
while (header)
|
||||
{
|
||||
refbuf_addref (header);
|
||||
header = header->next;
|
||||
}
|
||||
/* printf ("setting associated to %p\n", refbuf->associated); */
|
||||
}
|
||||
return refbuf;
|
||||
@ -299,7 +305,6 @@ static refbuf_t *get_buffer_finished (vstate_t *source_vorbis)
|
||||
source_vorbis->headers_head = NULL;
|
||||
source_vorbis->headers_tail = NULL;
|
||||
source_vorbis->get_buffer_page = get_buffer_header;
|
||||
/* printf ("stream cleared\n"); */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
58
src/refbuf.c
58
src/refbuf.c
@ -33,48 +33,50 @@ void refbuf_shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void refbuf_free (refbuf_t *refbuf)
|
||||
{
|
||||
free (refbuf->data);
|
||||
free (refbuf);
|
||||
}
|
||||
|
||||
|
||||
refbuf_t *refbuf_new(unsigned long size)
|
||||
{
|
||||
refbuf_t *refbuf;
|
||||
|
||||
refbuf = malloc (sizeof(refbuf_t));
|
||||
if (refbuf)
|
||||
refbuf = (refbuf_t *)malloc(sizeof(refbuf_t));
|
||||
if (refbuf == NULL)
|
||||
return NULL;
|
||||
refbuf->data = NULL;
|
||||
if (size)
|
||||
{
|
||||
refbuf->data = NULL;
|
||||
if (size && (refbuf->data = malloc (size)) == NULL)
|
||||
refbuf->data = malloc (size);
|
||||
if (refbuf->data == NULL)
|
||||
{
|
||||
free (refbuf);
|
||||
return NULL;
|
||||
}
|
||||
refbuf->len = 0;
|
||||
refbuf->sync_point = 0;
|
||||
refbuf->allocated = size;
|
||||
refbuf->next = NULL;
|
||||
refbuf->associated = NULL;
|
||||
refbuf->refbuf_associated_release = refbuf_free;
|
||||
refbuf->refbuf_release = refbuf_free;
|
||||
}
|
||||
refbuf->len = size;
|
||||
refbuf->sync_point = 0;
|
||||
refbuf->_count = 1;
|
||||
refbuf->next = NULL;
|
||||
refbuf->associated = NULL;
|
||||
|
||||
return refbuf;
|
||||
}
|
||||
|
||||
|
||||
void refbuf_release(refbuf_t *refbuf)
|
||||
void refbuf_addref(refbuf_t *self)
|
||||
{
|
||||
while (refbuf->associated)
|
||||
{
|
||||
refbuf_t *ref = refbuf->associated;
|
||||
refbuf->associated = ref->next;
|
||||
refbuf->refbuf_associated_release (ref);
|
||||
}
|
||||
refbuf->refbuf_release (refbuf);
|
||||
self->_count++;
|
||||
}
|
||||
|
||||
void refbuf_release(refbuf_t *self)
|
||||
{
|
||||
self->_count--;
|
||||
if (self->_count == 0) {
|
||||
while (self->associated)
|
||||
{
|
||||
refbuf_t *ref = self->associated;
|
||||
self->associated = ref->next;
|
||||
refbuf_release (ref);
|
||||
}
|
||||
if (self->len)
|
||||
free(self->data);
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
17
src/refbuf.h
17
src/refbuf.h
@ -21,31 +21,20 @@
|
||||
typedef struct _refbuf_tag
|
||||
{
|
||||
char *data;
|
||||
unsigned len;
|
||||
unsigned allocated;
|
||||
int idx;
|
||||
unsigned int len;
|
||||
int sync_point;
|
||||
struct _refbuf_tag *associated;
|
||||
void (*refbuf_associated_release)(struct _refbuf_tag *);
|
||||
void (*refbuf_release)(struct _refbuf_tag *);
|
||||
|
||||
struct _refbuf_tag *next;
|
||||
unsigned long _count;
|
||||
} refbuf_t;
|
||||
|
||||
void refbuf_initialize(void);
|
||||
void refbuf_shutdown(void);
|
||||
|
||||
void refbuf_free (refbuf_t *refbuf);
|
||||
refbuf_t *refbuf_new(unsigned long size);
|
||||
void refbuf_addref(refbuf_t *self);
|
||||
void refbuf_release(refbuf_t *self);
|
||||
|
||||
|
||||
#endif /* __REFBUF_H__ */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -234,8 +234,6 @@ void source_clear_source (source_t *source)
|
||||
{
|
||||
refbuf_t *p = source->stream_data;
|
||||
source->stream_data = p->next;
|
||||
if (source->stream_data && p->associated == source->stream_data->associated)
|
||||
p->associated = NULL;
|
||||
refbuf_release (p);
|
||||
}
|
||||
source->stream_data_tail = NULL;
|
||||
@ -1019,12 +1017,10 @@ void source_main(source_t *source)
|
||||
if (remove_from_q)
|
||||
{
|
||||
refbuf_t *to_go = source->stream_data;
|
||||
/* associated data is shared so don't release it if the next refbuf refers to it */
|
||||
|
||||
if (to_go->next)
|
||||
{
|
||||
source->stream_data = to_go->next;
|
||||
if (to_go->associated == source->stream_data->associated)
|
||||
to_go->associated = NULL;
|
||||
source->queue_size -= to_go->len;
|
||||
if (source->burst_point == to_go)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user