From 700bd44fdaaa0b3ebc6924180daae8f5105d0cd8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 3 Jan 2009 23:29:45 +0100 Subject: input_stream: added tag() method The tag() method reads a tag from the stream. This replaces the meta_name and meta_title attributes. --- src/decoder_api.c | 124 +++++++++++++++++++++++-------------------------- src/decoder_internal.h | 7 ++- src/decoder_thread.c | 15 ++++-- src/input_curl.c | 35 +++++++++++++- src/input_stream.c | 14 ++++-- src/input_stream.h | 12 ++++- 6 files changed, 129 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/decoder_api.c b/src/decoder_api.c index 0f25daadb..1f5db3b72 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -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; - - /* 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; - - 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 (tag2 != NULL) - /* use the composite tag returned by - tag_add_stream_tags() */ - src = tag2; - - if (src != NULL) { - music_pipe_tag(src); - if (tag2 != NULL) - tag_free(tag2); - } + /* send stream tags */ + + if (update_stream_tag(decoder, is)) { + enum decoder_command cmd; - decoder->stream_tag_sent = true; + if (decoder->decoder_tag != NULL) { + /* merge with tag from decoder plugin */ + struct tag *tag; + + 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 (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); + + /* save the tag */ + + if (decoder->decoder_tag != NULL) + tag_free(decoder->decoder_tag); + decoder->decoder_tag = tag_dup(tag); + + /* check for a new stream tag */ - if (tag2 != NULL) - tag = tag2; + update_stream_tag(decoder, is); - cmd = do_send_tag(is, tag); + /* send tag to music pipe */ - if (tag2 != NULL) - tag_free(tag2); + if (decoder->stream_tag != NULL) { + /* merge with tag from input stream */ + struct tag *merged; - if (cmd == DECODE_COMMAND_NONE) - decoder->stream_tag_sent = true; + 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; } diff --git a/src/decoder_internal.h b/src/decoder_internal.h index 39d6fe8a7..bc10475b9 100644 --- a/src/decoder_internal.h +++ b/src/decoder_internal.h @@ -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 diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 35d6e3206..3baa228e3 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -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; } diff --git a/src/input_curl.c b/src/input_curl.c index eb2550c6d..93c12d98e 100644 --- a/src/input_curl.c +++ b/src/input_curl.c @@ -20,6 +20,7 @@ #include "input_stream.h" #include "dlist.h" #include "config.h" +#include "tag.h" #include #include @@ -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, diff --git a/src/input_stream.c b/src/input_stream.c index 3df8fe006..f69debbf9 100644 --- a/src/input_stream.c +++ b/src/input_stream.c @@ -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) diff --git a/src/input_stream.h b/src/input_stream.h index 7ed0039a3..5761adc12 100644 --- a/src/input_stream.h +++ b/src/input_stream.h @@ -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); -- cgit v1.2.3