input_stream: added tag() method
The tag() method reads a tag from the stream. This replaces the meta_name and meta_title attributes.
This commit is contained in:
parent
4be479d20c
commit
700bd44fda
@ -38,7 +38,8 @@ void decoder_initialized(struct decoder * decoder,
|
||||
{
|
||||
assert(dc.state == DECODE_STATE_START);
|
||||
assert(decoder != NULL);
|
||||
assert(!decoder->stream_tag_sent);
|
||||
assert(decoder->stream_tag == NULL);
|
||||
assert(decoder->decoder_tag == NULL);
|
||||
assert(!decoder->seeking);
|
||||
assert(audio_format != NULL);
|
||||
assert(audio_format_defined(audio_format));
|
||||
@ -134,33 +135,6 @@ size_t decoder_read(struct decoder *decoder,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the tag items from the input stream (meta_name, meta_title) to
|
||||
* a duplicate of the specified tag. The return value has to be freed
|
||||
* with tag_free(). If this function returns NULL, then there are no
|
||||
* tags provided by the stream.
|
||||
*/
|
||||
static struct tag *
|
||||
tag_add_stream_tags(const struct tag *src_tag, const struct input_stream *is)
|
||||
{
|
||||
struct tag *tag;
|
||||
|
||||
assert(src_tag != NULL);
|
||||
assert(is != NULL);
|
||||
|
||||
if ((is->meta_name == NULL || tag_has_type(src_tag, TAG_ITEM_NAME)) &&
|
||||
(is->meta_title == NULL || tag_has_type(src_tag, TAG_ITEM_TITLE)))
|
||||
return NULL;
|
||||
|
||||
tag = tag_dup(src_tag);
|
||||
if (is->meta_name != NULL && !tag_has_type(src_tag, TAG_ITEM_NAME))
|
||||
tag_add_item(tag, TAG_ITEM_NAME, is->meta_name);
|
||||
if (is->meta_title != NULL && !tag_has_type(src_tag, TAG_ITEM_TITLE))
|
||||
tag_add_item(tag, TAG_ITEM_TITLE, is->meta_title);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* All chunks are full of decoded data; wait for the player to free
|
||||
* one.
|
||||
@ -195,6 +169,25 @@ do_send_tag(struct input_stream *is, const struct tag *tag)
|
||||
return DECODE_COMMAND_NONE;
|
||||
}
|
||||
|
||||
static bool
|
||||
update_stream_tag(struct decoder *decoder, struct input_stream *is)
|
||||
{
|
||||
struct tag *tag;
|
||||
|
||||
if (is == NULL)
|
||||
return false;
|
||||
|
||||
tag = input_stream_tag(is);
|
||||
if (tag == NULL)
|
||||
return false;
|
||||
|
||||
if (decoder->stream_tag != NULL)
|
||||
tag_free(decoder->stream_tag);
|
||||
|
||||
decoder->stream_tag = tag;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum decoder_command
|
||||
decoder_data(struct decoder *decoder,
|
||||
struct input_stream *is,
|
||||
@ -214,36 +207,25 @@ decoder_data(struct decoder *decoder,
|
||||
length == 0)
|
||||
return dc.command;
|
||||
|
||||
if (is != NULL && !decoder->stream_tag_sent) {
|
||||
const struct tag *src;
|
||||
struct tag *tag1, *tag2;
|
||||
/* send stream tags */
|
||||
|
||||
/* base is the current song's tag, or an empty new
|
||||
tag if the song has no tag */
|
||||
src = dc.current_song->tag;
|
||||
if (src == NULL)
|
||||
src = tag1 = tag_new();
|
||||
else
|
||||
tag1 = NULL;
|
||||
if (update_stream_tag(decoder, is)) {
|
||||
enum decoder_command cmd;
|
||||
|
||||
tag2 = tag_add_stream_tags(src, is);
|
||||
if (tag1 != NULL)
|
||||
/* free the empty tag created by tag_new(), we
|
||||
aren't going to send it */
|
||||
tag_free(tag1);
|
||||
if (decoder->decoder_tag != NULL) {
|
||||
/* merge with tag from decoder plugin */
|
||||
struct tag *tag;
|
||||
|
||||
if (tag2 != NULL)
|
||||
/* use the composite tag returned by
|
||||
tag_add_stream_tags() */
|
||||
src = tag2;
|
||||
tag = tag_merge(decoder->stream_tag,
|
||||
decoder->decoder_tag);
|
||||
cmd = do_send_tag(is, tag);
|
||||
tag_free(tag);
|
||||
} else
|
||||
/* send only the stream tag */
|
||||
cmd = do_send_tag(is, decoder->stream_tag);
|
||||
|
||||
if (src != NULL) {
|
||||
music_pipe_tag(src);
|
||||
if (tag2 != NULL)
|
||||
tag_free(tag2);
|
||||
}
|
||||
|
||||
decoder->stream_tag_sent = true;
|
||||
if (cmd != DECODE_COMMAND_NONE)
|
||||
return cmd;
|
||||
}
|
||||
|
||||
if (audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) {
|
||||
@ -299,21 +281,33 @@ enum decoder_command
|
||||
decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
|
||||
const struct tag *tag)
|
||||
{
|
||||
struct tag *tag2 = is != NULL ? tag_add_stream_tags(tag, is) : NULL;
|
||||
enum decoder_command cmd;
|
||||
|
||||
assert(dc.state == DECODE_STATE_DECODE);
|
||||
assert(tag != NULL);
|
||||
|
||||
if (tag2 != NULL)
|
||||
tag = tag2;
|
||||
/* save the tag */
|
||||
|
||||
cmd = do_send_tag(is, tag);
|
||||
if (decoder->decoder_tag != NULL)
|
||||
tag_free(decoder->decoder_tag);
|
||||
decoder->decoder_tag = tag_dup(tag);
|
||||
|
||||
if (tag2 != NULL)
|
||||
tag_free(tag2);
|
||||
/* check for a new stream tag */
|
||||
|
||||
if (cmd == DECODE_COMMAND_NONE)
|
||||
decoder->stream_tag_sent = true;
|
||||
update_stream_tag(decoder, is);
|
||||
|
||||
/* send tag to music pipe */
|
||||
|
||||
if (decoder->stream_tag != NULL) {
|
||||
/* merge with tag from input stream */
|
||||
struct tag *merged;
|
||||
|
||||
merged = tag_merge(decoder->stream_tag, decoder->decoder_tag);
|
||||
cmd = do_send_tag(is, merged);
|
||||
tag_free(merged);
|
||||
} else
|
||||
/* send only the decoder tag */
|
||||
cmd = do_send_tag(is, tag);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
@ -27,8 +27,11 @@ struct decoder {
|
||||
|
||||
bool seeking;
|
||||
|
||||
/** has the tag from the input stream been sent yet? */
|
||||
bool stream_tag_sent;
|
||||
/** the last tag received from the stream */
|
||||
struct tag *stream_tag;
|
||||
|
||||
/** the last tag received from the decoder plugin */
|
||||
struct tag *decoder_tag;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -38,7 +38,8 @@ decoder_stream_decode(const struct decoder_plugin *plugin,
|
||||
assert(plugin != NULL);
|
||||
assert(plugin->stream_decode != NULL);
|
||||
assert(decoder != NULL);
|
||||
assert(!decoder->stream_tag_sent);
|
||||
assert(decoder->stream_tag == NULL);
|
||||
assert(decoder->decoder_tag == NULL);
|
||||
assert(input_stream != NULL);
|
||||
assert(input_stream->ready);
|
||||
assert(dc.state == DECODE_STATE_START);
|
||||
@ -61,7 +62,8 @@ decoder_file_decode(const struct decoder_plugin *plugin,
|
||||
assert(plugin != NULL);
|
||||
assert(plugin->file_decode != NULL);
|
||||
assert(decoder != NULL);
|
||||
assert(!decoder->stream_tag_sent);
|
||||
assert(decoder->stream_tag == NULL);
|
||||
assert(decoder->decoder_tag == NULL);
|
||||
assert(path != NULL);
|
||||
assert(path[0] == '/');
|
||||
assert(dc.state == DECODE_STATE_START);
|
||||
@ -88,7 +90,8 @@ static void decoder_run_song(const struct song *song, const char *uri)
|
||||
}
|
||||
|
||||
decoder.seeking = false;
|
||||
decoder.stream_tag_sent = false;
|
||||
decoder.stream_tag = NULL;
|
||||
decoder.decoder_tag = NULL;
|
||||
|
||||
dc.state = DECODE_STATE_START;
|
||||
dc.command = DECODE_COMMAND_NONE;
|
||||
@ -186,6 +189,12 @@ static void decoder_run_song(const struct song *song, const char *uri)
|
||||
if (close_instream)
|
||||
input_stream_close(&input_stream);
|
||||
|
||||
if (decoder.stream_tag != NULL)
|
||||
tag_free(decoder.stream_tag);
|
||||
|
||||
if (decoder.decoder_tag != NULL)
|
||||
tag_free(decoder.decoder_tag);
|
||||
|
||||
dc.state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "input_stream.h"
|
||||
#include "dlist.h"
|
||||
#include "config.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/select.h>
|
||||
@ -73,6 +74,13 @@ struct input_curl {
|
||||
|
||||
/** error message provided by libcurl */
|
||||
char error[CURL_ERROR_SIZE];
|
||||
|
||||
/** the stream name from the icy-name response header */
|
||||
char *meta_name;
|
||||
|
||||
/** the tag object ready to be requested via
|
||||
input_stream_tag() */
|
||||
struct tag *tag;
|
||||
};
|
||||
|
||||
/** libcurl should accept "ICY 200 OK" */
|
||||
@ -137,6 +145,9 @@ input_curl_free(struct input_stream *is)
|
||||
{
|
||||
struct input_curl *c = is->data;
|
||||
|
||||
if (c->tag != NULL)
|
||||
tag_free(c->tag);
|
||||
|
||||
input_curl_easy_free(c);
|
||||
|
||||
if (c->multi != NULL)
|
||||
@ -146,6 +157,16 @@ input_curl_free(struct input_stream *is)
|
||||
g_free(c);
|
||||
}
|
||||
|
||||
static struct tag *
|
||||
input_curl_tag(struct input_stream *is)
|
||||
{
|
||||
struct input_curl *c = is->data;
|
||||
struct tag *tag = c->tag;
|
||||
|
||||
c->tag = NULL;
|
||||
return tag;
|
||||
}
|
||||
|
||||
static bool
|
||||
input_curl_multi_info_read(struct input_stream *is)
|
||||
{
|
||||
@ -367,6 +388,7 @@ static size_t
|
||||
input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
struct input_stream *is = stream;
|
||||
struct input_curl *c = is->data;
|
||||
const char *header = ptr, *end, *value;
|
||||
char name[64];
|
||||
|
||||
@ -410,8 +432,14 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
} else if (strcasecmp(name, "icy-name") == 0 ||
|
||||
strcasecmp(name, "ice-name") == 0 ||
|
||||
strcasecmp(name, "x-audiocast-name") == 0) {
|
||||
g_free(is->meta_name);
|
||||
is->meta_name = g_strndup(value, end - value);
|
||||
g_free(c->meta_name);
|
||||
c->meta_name = g_strndup(value, end - value);
|
||||
|
||||
if (c->tag != NULL)
|
||||
tag_free(c->tag);
|
||||
|
||||
c->tag = tag_new();
|
||||
tag_add_item(c->tag, TAG_ITEM_NAME, c->meta_name);
|
||||
}
|
||||
|
||||
return size;
|
||||
@ -691,6 +719,8 @@ input_curl_open(struct input_stream *is, const char *url)
|
||||
return false;
|
||||
}
|
||||
|
||||
c->tag = NULL;
|
||||
|
||||
ret = input_curl_easy_init(is);
|
||||
if (!ret) {
|
||||
input_curl_free(is);
|
||||
@ -709,6 +739,7 @@ input_curl_open(struct input_stream *is, const char *url)
|
||||
const struct input_plugin input_plugin_curl = {
|
||||
.open = input_curl_open,
|
||||
.close = input_curl_close,
|
||||
.tag = input_curl_tag,
|
||||
.buffer = input_curl_buffer,
|
||||
.read = input_curl_read,
|
||||
.eof = input_curl_eof,
|
||||
|
@ -68,8 +68,6 @@ input_stream_open(struct input_stream *is, const char *url)
|
||||
is->size = -1;
|
||||
is->error = 0;
|
||||
is->mime = NULL;
|
||||
is->meta_name = NULL;
|
||||
is->meta_title = NULL;
|
||||
|
||||
for (unsigned i = 0; i < num_input_plugins; ++i) {
|
||||
const struct input_plugin *plugin = input_plugins[i];
|
||||
@ -89,6 +87,16 @@ input_stream_seek(struct input_stream *is, off_t offset, int whence)
|
||||
return is->plugin->seek(is, offset, whence);
|
||||
}
|
||||
|
||||
struct tag *
|
||||
input_stream_tag(struct input_stream *is)
|
||||
{
|
||||
assert(is != NULL);
|
||||
|
||||
return is->plugin->tag != NULL
|
||||
? is->plugin->tag(is)
|
||||
: NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
input_stream_read(struct input_stream *is, void *ptr, size_t size)
|
||||
{
|
||||
@ -103,8 +111,6 @@ void input_stream_close(struct input_stream *is)
|
||||
is->plugin->close(is);
|
||||
|
||||
g_free(is->mime);
|
||||
g_free(is->meta_name);
|
||||
g_free(is->meta_title);
|
||||
}
|
||||
|
||||
bool input_stream_eof(struct input_stream *is)
|
||||
|
@ -29,6 +29,7 @@ struct input_plugin {
|
||||
bool (*open)(struct input_stream *is, const char *url);
|
||||
void (*close)(struct input_stream *is);
|
||||
|
||||
struct tag *(*tag)(struct input_stream *is);
|
||||
int (*buffer)(struct input_stream *is);
|
||||
size_t (*read)(struct input_stream *is, void *ptr, size_t size);
|
||||
bool (*eof)(struct input_stream *is);
|
||||
@ -46,8 +47,6 @@ struct input_stream {
|
||||
char *mime;
|
||||
|
||||
void *data;
|
||||
char *meta_name;
|
||||
char *meta_title;
|
||||
|
||||
void *archive;
|
||||
};
|
||||
@ -67,6 +66,15 @@ input_stream_seek(struct input_stream *is, off_t offset, int whence);
|
||||
void input_stream_close(struct input_stream *is);
|
||||
bool input_stream_eof(struct input_stream *is);
|
||||
|
||||
/**
|
||||
* Reads the tag from the stream.
|
||||
*
|
||||
* @return a tag object which must be freed with tag_free(), or NULL
|
||||
* if the tag has not changed since the last call
|
||||
*/
|
||||
struct tag *
|
||||
input_stream_tag(struct input_stream *is);
|
||||
|
||||
/* return value: -1 is error, 1 inidicates stuff was buffered, 0 means nothing
|
||||
was buffered */
|
||||
int input_stream_buffer(struct input_stream *is);
|
||||
|
Loading…
Reference in New Issue
Block a user