aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/decoder_api.c124
-rw-r--r--src/decoder_internal.h7
-rw-r--r--src/decoder_thread.c15
-rw-r--r--src/input_curl.c35
-rw-r--r--src/input_stream.c14
-rw-r--r--src/input_stream.h12
6 files changed, 129 insertions, 78 deletions
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));
@@ -135,33 +136,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 <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,
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);