33 struct xmms_xform_object_St {
37 struct xmms_xform_St {
39 struct xmms_xform_St *prev;
59 gboolean metadata_collected;
61 gboolean metadata_changed;
78 typedef struct xmms_xform_hotspot_St {
84 #define READ_CHUNK 4096
86 struct xmms_xform_plugin_St {
105 static void effect_callbacks_init (
void);
130 const gchar *url, gint nargs, gchar **args)
138 g_snprintf (bname,
sizeof (bname),
"%d", xform->browse_index++);
144 s = g_string_new (eurl);
146 for (i = 0; i < nargs; i++) {
147 g_string_append_c (s, i == 0 ?
'?' :
'&');
148 g_string_append (s, args[i]);
154 g_string_free (s, TRUE);
168 g_return_if_fail (xform);
169 g_return_if_fail (xform->browse_dict);
170 g_return_if_fail (key);
171 g_return_if_fail (val);
182 gchar *efile, *eurl, *t;
185 g_return_if_fail (filename);
187 t = strchr (filename,
'/');
188 g_return_if_fail (!t);
191 g_return_if_fail (url);
201 if (l && url[l - 1] ==
'/') {
202 t = g_strdup_printf (
"%s%s", eurl, efile);
204 t = g_strdup_printf (
"%s/%s", eurl, efile);
211 val = xform->browse_dict;
212 xform->browse_list = g_list_prepend (xform->browse_list, val);
220 xmms_browse_list_sortfunc (gconstpointer a, gconstpointer b)
223 xmmsv_t *val1, *val2, *tmp1, *tmp2;
224 const gchar *s1, *s2;
264 if (xform->plugin->methods.browse) {
265 if (!xform->plugin->methods.browse (xform, url, error)) {
268 list = xform->browse_list;
269 xform->browse_list = NULL;
270 list = g_list_sort (list, xmms_browse_list_sortfunc);
288 durl = g_strdup (url);
346 effect_callbacks_init ();
359 if (xform->plugin && xform->plugin->methods.destroy && xform->inited) {
360 xform->plugin->methods.destroy (xform);
363 g_hash_table_destroy (xform->metadata);
365 g_hash_table_destroy (xform->privdata);
366 g_queue_free (xform->hotspots);
368 g_free (xform->buffer);
388 xform->plugin = plugin;
389 xform->entry = entry;
390 xform->goal_hints = goal_hints;
391 xform->lr.bufend = &xform->lr.buf[0];
398 xform->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
402 xform->privdata = g_hash_table_new_full (g_str_hash, g_str_equal,
404 (GDestroyNotify) xmmsv_unref);
405 xform->hotspots = g_queue_new ();
407 if (plugin && entry) {
408 if (!plugin->methods.init (xform)) {
412 xform->inited = TRUE;
413 g_return_val_if_fail (xform->out_type, NULL);
444 va_start (ap, xform);
453 xform->out_type = type;
460 xform->out_type = xform->prev->out_type;
470 }
else if (xform->prev) {
491 return xform->out_type;
518 XMMS_DBG (
"Setting '%s' to %d", key, val);
519 g_hash_table_insert (xform->metadata, g_strdup (key),
521 xform->metadata_changed = TRUE;
530 if (!g_utf8_validate (val, -1, NULL)) {
536 if (strcmp (old, val) == 0) {
541 g_hash_table_insert (xform->metadata, g_strdup (key),
544 xform->metadata_changed = TRUE;
548 xmms_xform_metadata_get_val (
xmms_xform_t *xform,
const char *key)
552 for (; xform; xform = xform->prev) {
553 val = g_hash_table_lookup (xform->metadata, key);
565 return !!xmms_xform_metadata_get_val (xform, key);
573 gboolean ret = FALSE;
575 obj = xmms_xform_metadata_get_val (xform, key);
589 gboolean ret = FALSE;
591 obj = xmms_xform_metadata_get_val (xform, key);
604 } metadata_festate_t;
607 add_metadatum (gpointer _key, gpointer _value, gpointer user_data)
610 gchar *key = (gchar *) _key;
611 metadata_festate_t *st = (metadata_festate_t *) user_data;
635 xmms_xform_metadata_collect_one (
xmms_xform_t *xform, metadata_festate_t *info)
641 g_snprintf (src,
sizeof (src),
"plugin/%s",
645 g_hash_table_foreach (xform->metadata, add_metadatum, info);
647 xform->metadata_changed = FALSE;
651 xmms_xform_metadata_collect_r (
xmms_xform_t *xform, metadata_festate_t *info,
655 xmms_xform_metadata_collect_r (xform->prev, info, namestr);
660 g_string_append_c (namestr,
':');
665 if (xform->metadata_changed) {
666 xmms_xform_metadata_collect_one (xform, info);
669 xform->metadata_collected = TRUE;
673 xmms_xform_metadata_collect (
xmms_xform_t *start, GString *namestr, gboolean rehashing)
675 metadata_festate_t info;
680 info.entry = start->entry;
690 if (times_played < 0) {
700 xmms_xform_metadata_collect_r (start, &info, namestr);
708 times_played + (rehashing ? 0 : 1));
710 if (!rehashing || (rehashing && last_started)) {
711 g_get_current_time (&now);
715 (rehashing ? last_started : now.tv_sec));
728 metadata_festate_t info;
730 info.entry = xform->entry;
733 xmms_xform_metadata_collect_one (xform, &info);
745 hs->pos = xform->buffered;
749 g_queue_push_tail (xform->hotspots, hs);
756 xmms_xform_auxdata_set_val (xform, NULL, val);
763 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
774 if (strcmp (old, strval) == 0) {
780 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
785 gpointer data, gssize len)
790 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
794 xmms_xform_auxdata_get_val (
xmms_xform_t *xform,
const gchar *key)
804 for (i=0; (hs = g_queue_peek_nth (xform->hotspots, i)) != NULL; i++) {
807 }
else if (hs->key && !strcmp (key, hs->key)) {
813 val = g_hash_table_lookup (xform->privdata, key);
822 return !!xmms_xform_auxdata_get_val (xform, key);
830 obj = xmms_xform_auxdata_get_val (xform, key);
845 obj = xmms_xform_auxdata_get_val (xform, key);
856 const guchar **data, gsize *datalen)
860 obj = xmms_xform_auxdata_get_val (xform, key);
872 return (xform->plugin)
878 xmms_xform_this_peek (
xmms_xform_t *xform, gpointer buf, gint siz,
881 while (xform->buffered < siz) {
884 if (xform->buffered +
READ_CHUNK > xform->buffersize) {
885 xform->buffersize *= 2;
886 xform->buffer = g_realloc (xform->buffer, xform->buffersize);
889 res = xform->plugin->methods.read (xform,
890 &xform->buffer[xform->buffered],
894 XMMS_DBG (
"Read method of %s returned bad value (%d) - BUG IN PLUGIN",
902 }
else if (res == -1) {
906 xform->buffered += res;
911 siz =
MIN (siz, xform->buffered);
912 memcpy (buf, xform->buffer, siz);
917 xmms_xform_hotspot_callback (gpointer data, gpointer user_data)
920 gint *read = user_data;
931 hs = g_queue_peek_head (xform->hotspots);
932 while (hs != NULL && hs->pos == 0) {
933 g_queue_pop_head (xform->hotspots);
935 g_hash_table_insert (xform->privdata, hs->key, hs->obj);
937 hs = g_queue_peek_head (xform->hotspots);
960 nexths = xmms_xform_hotspots_update (xform);
962 siz =
MIN (siz, nexths);
965 if (xform->buffered) {
966 read =
MIN (siz, xform->buffered);
967 memcpy (buf, xform->buffer, read);
968 xform->buffered -= read;
971 g_queue_foreach (xform->hotspots, &xmms_xform_hotspot_callback, &read);
973 if (xform->buffered) {
976 memmove (xform->buffer, &xform->buffer[read], xform->buffered);
987 res = xform->plugin->methods.read (xform, buf + read, siz - read, err);
988 if (xform->metadata_collected && xform->metadata_changed)
989 xmms_xform_metadata_update (xform);
999 }
else if (res == -1) {
1000 xform->error = TRUE;
1004 xmms_xform_hotspots_update (xform);
1006 if (!g_queue_is_empty (xform->hotspots)) {
1007 if (xform->buffered + res > xform->buffersize) {
1008 xform->buffersize = MAX (xform->buffersize * 2,
1009 xform->buffersize + res);
1010 xform->buffer = g_realloc (xform->buffer,
1014 g_memmove (xform->buffer + xform->buffered, buf + read, res);
1015 xform->buffered += res;
1036 if (!xform->plugin->methods.seek) {
1043 offset -= xform->buffered;
1046 res = xform->plugin->methods.seek (xform, offset, whence, err);
1051 xform->buffered = 0;
1054 while ((hs = g_queue_pop_head (xform->hotspots)) != NULL) {
1068 g_return_val_if_fail (xform->prev, -1);
1069 return xmms_xform_this_peek (xform->prev, buf, siz, err);
1077 g_return_val_if_fail (xform, NULL);
1078 g_return_val_if_fail (line, NULL);
1080 p = strchr (xform->lr.buf,
'\n');
1091 xform->lr.bufend += r;
1093 if (xform->lr.bufend <= xform->lr.buf)
1096 *(xform->lr.bufend) =
'\0';
1097 p = strchr (xform->lr.buf,
'\n');
1099 p = xform->lr.bufend;
1103 if (p > xform->lr.buf && *(p-1) ==
'\r') {
1109 strcpy (line, xform->lr.buf);
1110 memmove (xform->lr.buf, p + 1, xform->lr.bufend - p);
1111 xform->lr.bufend -= (p - xform->lr.buf) + 1;
1112 *xform->lr.bufend =
'\0';
1120 g_return_val_if_fail (xform->prev, -1);
1128 g_return_val_if_fail (xform->prev, -1);
1135 const gchar *url = NULL;
1152 while (plugin->in_types) {
1155 plugin->in_types = g_list_delete_link (plugin->in_types,
1177 g_return_if_fail (plugin);
1180 XMMS_DBG (
"Registering xform '%s'",
1191 g_return_val_if_fail (plugin, FALSE);
1204 gchar *config_key, config_value[32];
1207 va_start (ap, plugin);
1211 config_key = g_strconcat (
"priority.",
1215 g_snprintf (config_value,
sizeof (config_value),
"%d", priority);
1217 config_value, NULL, NULL);
1218 g_free (config_key);
1220 plugin->in_types = g_list_prepend (plugin->in_types, t);
1229 for (t = plugin->in_types; t; t = g_list_next (t)) {
1235 config_key = g_strconcat (
"priority.",
1240 g_free (config_key);
1242 if (conf_priority) {
1254 typedef struct match_state_St {
1261 xmms_xform_match (
xmms_plugin_t *_plugin, gpointer user_data)
1269 if (!plugin->in_types) {
1275 if (xmms_xform_plugin_supports (plugin, state->out_type, &priority)) {
1276 XMMS_DBG (
"Plugin '%s' matched (priority %d)",
1278 if (priority > state->priority) {
1280 XMMS_DBG (
"Using plugin '%s' (priority %d) instead of '%s' (priority %d)",
1286 state->match = plugin;
1287 state->priority = priority;
1301 state.out_type = prev->out_type;
1303 state.priority = -1;
1310 XMMS_DBG (
"Found no matching plugin...");
1319 gboolean ret = TRUE;
1322 ret = xform->prev->eos;
1331 return xform->out_type;
1337 return xform->goal_hints;
1342 has_goalformat (
xmms_xform_t *xform, GList *goal_formats)
1345 gboolean ret = FALSE;
1350 for (n = goal_formats; n; n = g_list_next (n)) {
1360 XMMS_DBG (
"Not in one of %d goal-types", g_list_length (goal_formats));
1373 type = xform->out_type;
1375 if (strcmp (mime,
"audio/pcm") != 0) {
1414 durl = g_strdup (url);
1416 args = strchr (durl,
'?');
1424 params = g_strsplit (args,
"&", 0);
1426 for (i = 0; params && params[i]; i++) {
1428 v = strchr (params[i],
'=');
1437 g_strfreev (params);
1460 }
while (!has_goalformat (xform, goal_formats));
1462 outdata_type_metadata_collect (last);
1469 const gchar *url, gboolean rehashing)
1473 namestr = g_string_new (
"");
1474 xmms_xform_metadata_collect (xform, namestr, rehashing);
1475 xmms_log_info (
"Successfully setup chain for '%s' (%d) containing %s",
1476 url, entry, namestr->str);
1478 g_string_free (namestr, TRUE);
1506 if (!(url = get_url_for_entry (entry))) {
1518 GList *goal_formats, gboolean rehash)
1523 gboolean add_segment = FALSE;
1525 last = chain_setup (entry, url, goal_formats);
1537 add_segment = xmms_xform_plugin_supports (xform_plugin,
1545 last = xmms_xform_new_effect (last, entry, goal_formats,
"segment");
1553 last = add_effects (last, entry, goal_formats);
1559 chain_finalize (last, entry, url, rehash);
1566 const gchar *default_value,
1580 g_return_val_if_fail (xform->plugin, NULL);
1587 GList *goal_formats)
1591 for (effect_no = 0; TRUE; effect_no++) {
1596 g_snprintf (key,
sizeof (key),
"effect.order.%i", effect_no);
1609 last = xmms_xform_new_effect (last, entry, goal_formats, name);
1617 GList *goal_formats,
const gchar *name)
1630 if (!xmms_xform_plugin_supports (xform_plugin, last->out_type, NULL)) {
1631 xmms_log_info (
"Effect '%s' doesn't support format, skipping",
1637 xform =
xmms_xform_new (xform_plugin, last, entry, goal_formats);
1643 xmms_log_info (
"Effect '%s' failed to initialize, skipping",
1657 gint effect_no = GPOINTER_TO_INT (userdata);
1679 g_snprintf (key,
sizeof (key),
"effect.order.%i", effect_no + 1);
1684 GINT_TO_POINTER (effect_no + 1));
1690 effect_callbacks_init (
void)
1700 for (effect_no = 0; ; effect_no++) {
1701 g_snprintf (key,
sizeof (key),
"effect.order.%i", effect_no);
1708 GINT_TO_POINTER (effect_no));
1730 if ((!effect_no) || name[0]) {
1732 GINT_TO_POINTER (effect_no));
#define XMMS_CMD_FUNC(cmdid)
xmmsv_t * xmmsv_new_dict(void)
Allocates a new 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...
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.
#define xmms_object_unref(obj)
xmms_config_property_t * xmms_plugin_config_property_register(xmms_plugin_t *plugin, const gchar *name, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
struct xmms_stream_type_St xmms_stream_type_t
void xmms_object_cmd_add(xmms_object_t *object, guint cmdid, const xmms_object_cmd_desc_t *desc)
Add a command that could be called from the client API to a object.
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)
gint xmms_config_property_get_int(const xmms_config_property_t *prop)
Return the value of a config property as an int.
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).
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.
#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_CMD_DEFINE(cmdid, realfunc, argtype0, _rettype, argtype1, argtype2)
void xmms_ipc_object_unregister(xmms_ipc_objects_t objectid)
Remove a object from the IPC core.
#define xmms_log_info(fmt,...)
#define XMMS_STREAM_TYPE_PRIORITY_DEFAULT
void xmms_plugin_destroy(xmms_plugin_t *plugin)
xmmsv_t * xmmsv_new_bin(unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
#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,...)
G_BEGIN_DECLS enum xmms_stream_type_key_E xmms_stream_type_key_t
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)
void xmms_ipc_object_register(xmms_ipc_objects_t objectid, xmms_object_t *object)
Register a object to the IPC core.
void(* xmms_object_handler_t)(xmms_object_t *object, xmmsv_t *data, gpointer userdata)
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)