34 struct xmms_xform_object_St {
38 struct xmms_xform_St {
40 struct xmms_xform_St *prev;
60 gboolean metadata_collected;
62 gboolean metadata_changed;
79 typedef struct xmms_xform_hotspot_St {
85 #define READ_CHUNK 4096 99 static void effect_callbacks_init (
void);
103 #include "xform_ipc.c" 128 const gchar *url, gint nargs, gchar **args)
136 g_snprintf (bname,
sizeof (bname),
"%d", xform->browse_index++);
142 s = g_string_new (eurl);
144 for (i = 0; i < nargs; i++) {
145 g_string_append_c (s, i == 0 ?
'?' :
'&');
146 g_string_append (s, args[i]);
152 g_string_free (s, TRUE);
166 g_return_if_fail (xform);
167 g_return_if_fail (xform->browse_dict);
168 g_return_if_fail (key);
169 g_return_if_fail (val);
180 gchar *efile, *eurl, *t;
183 g_return_if_fail (filename);
185 t = strchr (filename,
'/');
186 g_return_if_fail (!t);
189 g_return_if_fail (url);
199 if (l && url[l - 1] ==
'/') {
200 t = g_strdup_printf (
"%s%s", eurl, efile);
202 t = g_strdup_printf (
"%s/%s", eurl, efile);
209 val = xform->browse_dict;
210 xform->browse_list = g_list_prepend (xform->browse_list, val);
218 xmms_browse_list_sortfunc (gconstpointer a, gconstpointer b)
221 xmmsv_t *val1, *val2, *tmp1, *tmp2;
222 const gchar *s1, *s2;
266 list = xform->browse_list;
267 xform->browse_list = NULL;
268 list = g_list_sort (list, xmms_browse_list_sortfunc);
286 durl = g_strdup (url);
327 xmms_xform_unregister_ipc_commands ();
337 xmms_xform_register_ipc_commands (
XMMS_OBJECT (obj));
339 effect_callbacks_init ();
352 if (xform->plugin && xform->inited) {
358 g_hash_table_destroy (xform->metadata);
360 g_hash_table_destroy (xform->privdata);
361 g_queue_free (xform->hotspots);
363 g_free (xform->buffer);
383 xform->plugin = plugin;
384 xform->entry = entry;
385 xform->goal_hints = goal_hints;
386 xform->lr.bufend = &xform->lr.buf[0];
393 xform->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
397 xform->privdata = g_hash_table_new_full (g_str_hash, g_str_equal,
400 xform->hotspots = g_queue_new ();
402 if (plugin && entry) {
407 xform->inited = TRUE;
408 g_return_val_if_fail (xform->out_type, NULL);
439 va_start (ap, xform);
448 xform->out_type = type;
455 xform->out_type = xform->prev->out_type;
465 }
else if (xform->prev) {
486 return xform->out_type;
513 XMMS_DBG (
"Setting '%s' to %d", key, val);
514 g_hash_table_insert (xform->metadata, g_strdup (key),
516 xform->metadata_changed = TRUE;
525 if (!g_utf8_validate (val, -1, NULL)) {
531 if (strcmp (old, val) == 0) {
536 g_hash_table_insert (xform->metadata, g_strdup (key),
539 xform->metadata_changed = TRUE;
543 xmms_xform_metadata_get_val (
xmms_xform_t *xform,
const char *key)
547 for (; xform; xform = xform->prev) {
548 val = g_hash_table_lookup (xform->metadata, key);
560 return !!xmms_xform_metadata_get_val (xform, key);
568 gboolean ret = FALSE;
570 obj = xmms_xform_metadata_get_val (xform, key);
584 gboolean ret = FALSE;
586 obj = xmms_xform_metadata_get_val (xform, key);
599 } metadata_festate_t;
602 add_metadatum (gpointer _key, gpointer _value, gpointer user_data)
605 gchar *key = (gchar *) _key;
606 metadata_festate_t *st = (metadata_festate_t *) user_data;
630 xmms_xform_metadata_collect_one (
xmms_xform_t *xform, metadata_festate_t *info)
636 g_snprintf (src,
sizeof (src),
"plugin/%s",
640 g_hash_table_foreach (xform->metadata, add_metadatum, info);
642 xform->metadata_changed = FALSE;
646 xmms_xform_metadata_collect_r (
xmms_xform_t *xform, metadata_festate_t *info,
650 xmms_xform_metadata_collect_r (xform->prev, info, namestr);
655 g_string_append_c (namestr,
':');
660 if (xform->metadata_changed) {
661 xmms_xform_metadata_collect_one (xform, info);
664 xform->metadata_collected = TRUE;
668 xmms_xform_metadata_collect (
xmms_xform_t *start, GString *namestr, gboolean rehashing)
670 metadata_festate_t info;
675 info.entry = start->entry;
685 if (times_played < 0) {
695 xmms_xform_metadata_collect_r (start, &info, namestr);
703 times_played + (rehashing ? 0 : 1));
705 if (!rehashing || (rehashing && last_started)) {
706 g_get_current_time (&now);
710 (rehashing ? last_started : now.tv_sec));
723 metadata_festate_t info;
725 info.entry = xform->entry;
728 xmms_xform_metadata_collect_one (xform, &info);
740 hs->pos = xform->buffered;
744 g_queue_push_tail (xform->hotspots, hs);
751 xmms_xform_auxdata_set_val (xform, NULL, val);
758 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
769 if (strcmp (old, strval) == 0) {
775 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
780 gpointer data, gssize len)
785 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
789 xmms_xform_auxdata_get_val (
xmms_xform_t *xform,
const gchar *key)
799 for (i=0; (hs = g_queue_peek_nth (xform->hotspots, i)) != NULL; i++) {
802 }
else if (hs->key && !strcmp (key, hs->key)) {
808 val = g_hash_table_lookup (xform->privdata, key);
817 return !!xmms_xform_auxdata_get_val (xform, key);
825 obj = xmms_xform_auxdata_get_val (xform, key);
840 obj = xmms_xform_auxdata_get_val (xform, key);
851 const guchar **data, gsize *datalen)
855 obj = xmms_xform_auxdata_get_val (xform, key);
867 return (xform->plugin)
873 xmms_xform_this_peek (
xmms_xform_t *xform, gpointer buf, gint siz,
876 while (xform->buffered < siz) {
879 if (xform->buffered +
READ_CHUNK > xform->buffersize) {
880 xform->buffersize *= 2;
881 xform->buffer = g_realloc (xform->buffer, xform->buffersize);
885 &xform->buffer[xform->buffered],
889 XMMS_DBG (
"Read method of %s returned bad value (%d) - BUG IN PLUGIN",
897 }
else if (res == -1) {
901 xform->buffered += res;
906 siz =
MIN (siz, xform->buffered);
907 memcpy (buf, xform->buffer, siz);
912 xmms_xform_hotspot_callback (gpointer data, gpointer user_data)
915 gint *read = user_data;
926 hs = g_queue_peek_head (xform->hotspots);
927 while (hs != NULL && hs->pos == 0) {
928 g_queue_pop_head (xform->hotspots);
930 g_hash_table_insert (xform->privdata, hs->key, hs->obj);
932 hs = g_queue_peek_head (xform->hotspots);
955 nexths = xmms_xform_hotspots_update (xform);
957 siz =
MIN (siz, nexths);
960 if (xform->buffered) {
961 read =
MIN (siz, xform->buffered);
962 memcpy (buf, xform->buffer, read);
963 xform->buffered -= read;
966 g_queue_foreach (xform->hotspots, &xmms_xform_hotspot_callback, &read);
968 if (xform->buffered) {
971 memmove (xform->buffer, &xform->buffer[read], xform->buffered);
983 if (xform->metadata_collected && xform->metadata_changed)
984 xmms_xform_metadata_update (xform);
994 }
else if (res == -1) {
999 xmms_xform_hotspots_update (xform);
1001 if (!g_queue_is_empty (xform->hotspots)) {
1002 if (xform->buffered + res > xform->buffersize) {
1003 xform->buffersize = MAX (xform->buffersize * 2,
1004 xform->buffersize + res);
1005 xform->buffer = g_realloc (xform->buffer,
1009 g_memmove (xform->buffer + xform->buffered, buf + read, res);
1010 xform->buffered += res;
1038 offset -= xform->buffered;
1046 xform->buffered = 0;
1049 while ((hs = g_queue_pop_head (xform->hotspots)) != NULL) {
1063 g_return_val_if_fail (xform->prev, -1);
1064 return xmms_xform_this_peek (xform->prev, buf, siz, err);
1072 g_return_val_if_fail (xform, NULL);
1073 g_return_val_if_fail (line, NULL);
1075 p = strchr (xform->lr.buf,
'\n');
1086 xform->lr.bufend += r;
1088 if (xform->lr.bufend <= xform->lr.buf)
1091 *(xform->lr.bufend) =
'\0';
1092 p = strchr (xform->lr.buf,
'\n');
1094 p = xform->lr.bufend;
1098 if (p > xform->lr.buf && *(p-1) ==
'\r') {
1104 strcpy (line, xform->lr.buf);
1105 memmove (xform->lr.buf, p + 1, xform->lr.bufend - p);
1106 xform->lr.bufend -= (p - xform->lr.buf) + 1;
1107 *xform->lr.bufend =
'\0';
1115 g_return_val_if_fail (xform->prev, -1);
1123 g_return_val_if_fail (xform->prev, -1);
1130 const gchar *url = NULL;
1143 typedef struct match_state_St {
1150 xmms_xform_match (
xmms_plugin_t *plugin, gpointer user_data)
1163 XMMS_DBG (
"Plugin '%s' matched (priority %d)",
1166 if (priority > state->priority) {
1169 XMMS_DBG (
"Using plugin '%s' (priority %d) instead of '%s' (priority %d)",
1175 state->match = xform_plugin;
1176 state->priority = priority;
1189 state.out_type = prev->out_type;
1191 state.priority = -1;
1198 XMMS_DBG (
"Found no matching plugin...");
1207 gboolean ret = TRUE;
1210 ret = xform->prev->eos;
1219 return xform->out_type;
1225 return xform->goal_hints;
1230 has_goalformat (
xmms_xform_t *xform, GList *goal_formats)
1233 gboolean ret = FALSE;
1238 for (n = goal_formats; n; n = g_list_next (n)) {
1248 XMMS_DBG (
"Not in one of %d goal-types", g_list_length (goal_formats));
1261 type = xform->out_type;
1263 if (strcmp (mime,
"audio/pcm") != 0) {
1302 durl = g_strdup (url);
1304 args = strchr (durl,
'?');
1312 params = g_strsplit (args,
"&", 0);
1314 for (i = 0; params && params[i]; i++) {
1316 v = strchr (params[i],
'=');
1325 g_strfreev (params);
1348 }
while (!has_goalformat (xform, goal_formats));
1350 outdata_type_metadata_collect (last);
1357 const gchar *url, gboolean rehashing)
1361 namestr = g_string_new (
"");
1362 xmms_xform_metadata_collect (xform, namestr, rehashing);
1363 xmms_log_info (
"Successfully setup chain for '%s' (%d) containing %s",
1364 url, entry, namestr->str);
1366 g_string_free (namestr, TRUE);
1394 if (!(url = get_url_for_entry (entry))) {
1406 GList *goal_formats, gboolean rehash)
1411 gboolean add_segment = FALSE;
1414 last = chain_setup (entry, url, goal_formats);
1434 last = xmms_xform_new_effect (last, entry, goal_formats,
"segment");
1442 last = add_effects (last, entry, goal_formats);
1448 chain_finalize (last, entry, url, rehash);
1455 g_return_val_if_fail (xform->plugin, NULL);
1462 GList *goal_formats)
1466 for (effect_no = 0; TRUE; effect_no++) {
1471 g_snprintf (key,
sizeof (key),
"effect.order.%i", effect_no);
1484 last = xmms_xform_new_effect (last, entry, goal_formats, name);
1492 GList *goal_formats,
const gchar *name)
1507 xmms_log_info (
"Effect '%s' doesn't support format, skipping",
1513 xform =
xmms_xform_new (xform_plugin, last, entry, goal_formats);
1519 xmms_log_info (
"Effect '%s' failed to initialize, skipping",
1533 gint effect_no = GPOINTER_TO_INT (userdata);
1555 g_snprintf (key,
sizeof (key),
"effect.order.%i", effect_no + 1);
1560 GINT_TO_POINTER (effect_no + 1));
1566 effect_callbacks_init (
void)
1576 for (effect_no = 0; ; effect_no++) {
1577 g_snprintf (key,
sizeof (key),
"effect.order.%i", effect_no);
1584 GINT_TO_POINTER (effect_no));
1606 if ((!effect_no) || name[0]) {
1608 GINT_TO_POINTER (effect_no));
enum xmms_stream_type_key_E xmms_stream_type_key_t
int xmmsv_dict_set(xmmsv_t *dictv, const char *key, xmmsv_t *val)
Insert an element under the given key in the dict xmmsv_t.
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed...
#define xmms_object_unref(obj)
struct xmms_stream_type_St xmms_stream_type_t
xmms_config_property_t * xmms_config_lookup(const gchar *path)
Look up a config key from the global config.
xmmsv_t * xmmsv_new_none(void)
Allocates a new empty xmmsv_t.
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
const gchar * xmms_plugin_shortname_get(const xmms_plugin_t *plugin)
xmmsv_t * xmmsv_new_dict(void)
Allocates a new dict xmmsv_t.
gboolean xmms_stream_type_match(const xmms_stream_type_t *in_type, const xmms_stream_type_t *out_type)
#define xmms_log_error(fmt,...)
void xmms_config_property_callback_set(xmms_config_property_t *prop, xmms_object_handler_t cb, gpointer userdata)
Set a callback function for a config property.
int xmmsv_dict_get(xmmsv_t *dictv, const char *key, xmmsv_t **val)
Get the element corresponding to the given key in the dict xmmsv_t (if it exists).
#define XMMS_PLUGIN_SHORTNAME_MAX_LEN
const gchar * xmms_config_property_get_string(const xmms_config_property_t *prop)
Return the value of a config property as a string.
gint xmms_natcmp(const gchar *str1, const gchar *str2)
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
void xmms_plugin_foreach(xmms_plugin_type_t type, xmms_plugin_foreach_func_t func, gpointer user_data)
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
#define xmms_log_info(fmt,...)
#define xmms_object_ref(obj)
int xmmsv_get_bin(const xmmsv_t *val, const unsigned char **r, unsigned int *rlen)
Retrieves binary data from the value.
#define XMMS_DBG(fmt,...)
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
#define xmms_object_new(objtype, destroyfunc)
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
xmms_config_property_t * xmms_config_property_register(const gchar *path, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Register a new config property.
xmms_config_property_t * xmms_plugin_config_lookup(xmms_plugin_t *plugin, const gchar *key)
struct xmms_config_property_St xmms_config_property_t
xmms_plugin_t * xmms_plugin_find(xmms_plugin_type_t type, const gchar *name)
const char * xmms_stream_type_get_str(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
xmmsv_t * xmmsv_new_bin(const unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)