input_curl: enabled Icy-Metadata support
This commit is contained in:
parent
f9e9089f42
commit
96c18e7d15
1
NEWS
1
NEWS
@ -11,6 +11,7 @@ ver 0.15 - (200?/??/??)
|
|||||||
* fall back to XDG music directory if no music_directory is configured
|
* fall back to XDG music directory if no music_directory is configured
|
||||||
* failure to read the state file is non-fatal
|
* failure to read the state file is non-fatal
|
||||||
* fix minor memory leak in decoder_tag()
|
* fix minor memory leak in decoder_tag()
|
||||||
|
* added Icy-Metadata support
|
||||||
|
|
||||||
ver 0.14 (2008/12/25)
|
ver 0.14 (2008/12/25)
|
||||||
* audio outputs:
|
* audio outputs:
|
||||||
|
@ -52,9 +52,11 @@ icy_reset(struct icy_metadata *im)
|
|||||||
size_t
|
size_t
|
||||||
icy_data(struct icy_metadata *im, size_t length)
|
icy_data(struct icy_metadata *im, size_t length)
|
||||||
{
|
{
|
||||||
assert(icy_defined(im));
|
|
||||||
assert(length > 0);
|
assert(length > 0);
|
||||||
|
|
||||||
|
if (!icy_defined(im))
|
||||||
|
return length;
|
||||||
|
|
||||||
if (im->data_rest == 0)
|
if (im->data_rest == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ icy_meta(struct icy_metadata *im, const void *data, size_t length)
|
|||||||
if (length > im->meta_size - im->meta_position)
|
if (length > im->meta_size - im->meta_position)
|
||||||
length = im->meta_size - im->meta_position;
|
length = im->meta_size - im->meta_position;
|
||||||
|
|
||||||
memcpy(im->meta_data + im->meta_position, data, length);
|
memcpy(im->meta_data + im->meta_position, p, length);
|
||||||
im->meta_position += length;
|
im->meta_position += length;
|
||||||
|
|
||||||
if (p != data)
|
if (p != data)
|
||||||
|
103
src/input_curl.c
103
src/input_curl.c
@ -21,6 +21,7 @@
|
|||||||
#include "dlist.h"
|
#include "dlist.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
|
#include "icy_metadata.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
@ -75,6 +76,9 @@ struct input_curl {
|
|||||||
/** error message provided by libcurl */
|
/** error message provided by libcurl */
|
||||||
char error[CURL_ERROR_SIZE];
|
char error[CURL_ERROR_SIZE];
|
||||||
|
|
||||||
|
/** parser for icy-metadata */
|
||||||
|
struct icy_metadata icy_metadata;
|
||||||
|
|
||||||
/** the stream name from the icy-name response header */
|
/** the stream name from the icy-name response header */
|
||||||
char *meta_name;
|
char *meta_name;
|
||||||
|
|
||||||
@ -147,6 +151,7 @@ input_curl_free(struct input_stream *is)
|
|||||||
|
|
||||||
if (c->tag != NULL)
|
if (c->tag != NULL)
|
||||||
tag_free(c->tag);
|
tag_free(c->tag);
|
||||||
|
g_free(c->meta_name);
|
||||||
|
|
||||||
input_curl_easy_free(c);
|
input_curl_easy_free(c);
|
||||||
|
|
||||||
@ -254,18 +259,66 @@ consume_buffer(struct buffer *buffer, size_t length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
read_from_buffer(struct buffer *buffer, void *dest, size_t length,
|
read_from_buffer(struct icy_metadata *icy_metadata, struct buffer *buffer,
|
||||||
|
void *dest0, size_t length,
|
||||||
struct list_head *rewind_head)
|
struct list_head *rewind_head)
|
||||||
{
|
{
|
||||||
|
uint8_t *dest = dest0;
|
||||||
|
size_t nbytes = 0;
|
||||||
|
|
||||||
assert(buffer->size > 0);
|
assert(buffer->size > 0);
|
||||||
assert(buffer->consumed < buffer->size);
|
assert(buffer->consumed < buffer->size);
|
||||||
|
|
||||||
if (length > buffer->size - buffer->consumed)
|
if (length > buffer->size - buffer->consumed)
|
||||||
length = buffer->size - buffer->consumed;
|
length = buffer->size - buffer->consumed;
|
||||||
|
|
||||||
memcpy(dest, buffer->data + buffer->consumed, length);
|
while (true) {
|
||||||
consume_buffer(buffer, length, rewind_head);
|
size_t chunk;
|
||||||
return length;
|
|
||||||
|
chunk = icy_data(icy_metadata, length);
|
||||||
|
if (chunk > 0) {
|
||||||
|
memcpy(dest, buffer->data + buffer->consumed,
|
||||||
|
chunk);
|
||||||
|
consume_buffer(buffer, chunk, rewind_head);
|
||||||
|
|
||||||
|
nbytes += chunk;
|
||||||
|
dest += chunk;
|
||||||
|
length -= chunk;
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = icy_meta(icy_metadata, buffer->data + buffer->consumed,
|
||||||
|
length);
|
||||||
|
if (chunk > 0) {
|
||||||
|
consume_buffer(buffer, chunk, rewind_head);
|
||||||
|
|
||||||
|
length -= chunk;
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copy_icy_tag(struct input_curl *c)
|
||||||
|
{
|
||||||
|
struct tag *tag = icy_tag(&c->icy_metadata);
|
||||||
|
|
||||||
|
if (tag == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (c->tag != NULL)
|
||||||
|
tag_free(c->tag);
|
||||||
|
|
||||||
|
if (c->meta_name != NULL && !tag_has_type(tag, TAG_ITEM_NAME))
|
||||||
|
tag_add_item(tag, TAG_ITEM_NAME, c->meta_name);
|
||||||
|
|
||||||
|
c->tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
@ -317,13 +370,17 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size)
|
|||||||
|
|
||||||
while (size > 0 && !list_empty(&c->buffers)) {
|
while (size > 0 && !list_empty(&c->buffers)) {
|
||||||
struct buffer *buffer = (struct buffer *)c->buffers.next;
|
struct buffer *buffer = (struct buffer *)c->buffers.next;
|
||||||
size_t copy = read_from_buffer(buffer, dest + nbytes, size,
|
size_t copy = read_from_buffer(&c->icy_metadata, buffer,
|
||||||
|
dest + nbytes, size,
|
||||||
rewind_head);
|
rewind_head);
|
||||||
|
|
||||||
nbytes += copy;
|
nbytes += copy;
|
||||||
size -= copy;
|
size -= copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (icy_defined(&c->icy_metadata))
|
||||||
|
copy_icy_tag(c);
|
||||||
|
|
||||||
is->offset += (off_t)nbytes;
|
is->offset += (off_t)nbytes;
|
||||||
|
|
||||||
if (rewind_head != NULL && is->offset > max_rewind_size) {
|
if (rewind_head != NULL && is->offset > max_rewind_size) {
|
||||||
@ -414,9 +471,11 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
|||||||
while (end > value && g_ascii_isspace(end[-1]))
|
while (end > value && g_ascii_isspace(end[-1]))
|
||||||
--end;
|
--end;
|
||||||
|
|
||||||
if (strcasecmp(name, "accept-ranges") == 0)
|
if (strcasecmp(name, "accept-ranges") == 0) {
|
||||||
is->seekable = true;
|
/* a stream with icy-metadata is not seekable */
|
||||||
else if (strcasecmp(name, "content-length") == 0) {
|
if (!icy_defined(&c->icy_metadata))
|
||||||
|
is->seekable = true;
|
||||||
|
} else if (strcasecmp(name, "content-length") == 0) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
|
|
||||||
if ((size_t)(end - header) >= sizeof(buffer))
|
if ((size_t)(end - header) >= sizeof(buffer))
|
||||||
@ -440,6 +499,27 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
|||||||
|
|
||||||
c->tag = tag_new();
|
c->tag = tag_new();
|
||||||
tag_add_item(c->tag, TAG_ITEM_NAME, c->meta_name);
|
tag_add_item(c->tag, TAG_ITEM_NAME, c->meta_name);
|
||||||
|
} else if (strcasecmp(name, "icy-metaint") == 0) {
|
||||||
|
char buffer[64];
|
||||||
|
size_t icy_metaint;
|
||||||
|
|
||||||
|
if ((size_t)(end - header) >= sizeof(buffer) ||
|
||||||
|
icy_defined(&c->icy_metadata))
|
||||||
|
return size;
|
||||||
|
|
||||||
|
memcpy(buffer, value, end - value);
|
||||||
|
buffer[end - value] = 0;
|
||||||
|
|
||||||
|
icy_metaint = g_ascii_strtoull(buffer, NULL, 10);
|
||||||
|
g_debug("icy-metaint=%zu", icy_metaint);
|
||||||
|
|
||||||
|
if (icy_metaint > 0) {
|
||||||
|
icy_start(&c->icy_metadata, icy_metaint);
|
||||||
|
|
||||||
|
/* a stream with icy-metadata is not
|
||||||
|
seekable */
|
||||||
|
is->seekable = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
@ -507,10 +587,8 @@ input_curl_easy_init(struct input_stream *is)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
c->request_headers = NULL;
|
c->request_headers = NULL;
|
||||||
/*
|
|
||||||
c->request_headers = curl_slist_append(c->request_headers,
|
c->request_headers = curl_slist_append(c->request_headers,
|
||||||
"Icy-Metadata: 1");
|
"Icy-Metadata: 1");
|
||||||
*/
|
|
||||||
curl_easy_setopt(c->easy, CURLOPT_HTTPHEADER, c->request_headers);
|
curl_easy_setopt(c->easy, CURLOPT_HTTPHEADER, c->request_headers);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -590,6 +668,10 @@ input_curl_rewind(struct input_stream *is)
|
|||||||
|
|
||||||
list_splice_init(&c->rewind, &c->buffers);
|
list_splice_init(&c->rewind, &c->buffers);
|
||||||
is->offset = 0;
|
is->offset = 0;
|
||||||
|
|
||||||
|
/* rewind the icy_metadata object */
|
||||||
|
|
||||||
|
icy_reset(&c->icy_metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -719,6 +801,7 @@ input_curl_open(struct input_stream *is, const char *url)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icy_clear(&c->icy_metadata);
|
||||||
c->tag = NULL;
|
c->tag = NULL;
|
||||||
|
|
||||||
ret = input_curl_easy_init(is);
|
ret = input_curl_easy_init(is);
|
||||||
|
Loading…
Reference in New Issue
Block a user