00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <string.h>
00023
00024 #include "xmmspriv/xmms_plugin.h"
00025 #include "xmmspriv/xmms_xform.h"
00026 #include "xmmspriv/xmms_streamtype.h"
00027 #include "xmmspriv/xmms_medialib.h"
00028 #include "xmmspriv/xmms_utils.h"
00029 #include "xmmspriv/xmms_xform_plugin.h"
00030 #include "xmms/xmms_ipc.h"
00031 #include "xmms/xmms_log.h"
00032 #include "xmms/xmms_object.h"
00033
00034 struct xmms_xform_object_St {
00035 xmms_object_t obj;
00036 };
00037
00038 struct xmms_xform_St {
00039 xmms_object_t obj;
00040 struct xmms_xform_St *prev;
00041
00042 const xmms_xform_plugin_t *plugin;
00043 xmms_medialib_entry_t entry;
00044
00045 gboolean inited;
00046
00047 void *priv;
00048
00049 xmms_stream_type_t *out_type;
00050
00051 GList *goal_hints;
00052
00053 gboolean eos;
00054 gboolean error;
00055
00056 char *buffer;
00057 gint buffered;
00058 gint buffersize;
00059
00060 gboolean metadata_collected;
00061
00062 gboolean metadata_changed;
00063 GHashTable *metadata;
00064
00065 GHashTable *privdata;
00066 GQueue *hotspots;
00067
00068 GList *browse_list;
00069 xmmsv_t *browse_dict;
00070 gint browse_index;
00071
00072
00073 struct {
00074 gchar buf[XMMS_XFORM_MAX_LINE_SIZE];
00075 gchar *bufend;
00076 } lr;
00077 };
00078
00079 typedef struct xmms_xform_hotspot_St {
00080 guint pos;
00081 gchar *key;
00082 xmmsv_t *obj;
00083 } xmms_xform_hotspot_t;
00084
00085 #define READ_CHUNK 4096
00086
00087
00088 xmms_xform_t *xmms_xform_find (xmms_xform_t *prev, xmms_medialib_entry_t entry,
00089 GList *goal_hints);
00090 const char *xmms_xform_shortname (xmms_xform_t *xform);
00091 static xmms_xform_t *add_effects (xmms_xform_t *last,
00092 xmms_medialib_entry_t entry,
00093 GList *goal_formats);
00094 static xmms_xform_t *xmms_xform_new_effect (xmms_xform_t* last,
00095 xmms_medialib_entry_t entry,
00096 GList *goal_formats,
00097 const gchar *name);
00098 static void xmms_xform_destroy (xmms_object_t *object);
00099 static void effect_callbacks_init (void);
00100
00101 static GList *xmms_xform_client_browse (xmms_xform_object_t *obj, const gchar *url, xmms_error_t *error);
00102
00103 #include "xform_ipc.c"
00104
00105 void
00106 xmms_xform_browse_add_entry_property_str (xmms_xform_t *xform,
00107 const gchar *key,
00108 const gchar *value)
00109 {
00110 xmmsv_t *val = xmmsv_new_string (value);
00111 xmms_xform_browse_add_entry_property (xform, key, val);
00112 xmmsv_unref (val);
00113 }
00114
00115
00116 void
00117 xmms_xform_browse_add_entry_property_int (xmms_xform_t *xform,
00118 const gchar *key,
00119 gint value)
00120 {
00121 xmmsv_t *val = xmmsv_new_int (value);
00122 xmms_xform_browse_add_entry_property (xform, key, val);
00123 xmmsv_unref (val);
00124 }
00125
00126 void
00127 xmms_xform_browse_add_symlink_args (xmms_xform_t *xform, const gchar *basename,
00128 const gchar *url, gint nargs, gchar **args)
00129 {
00130 GString *s;
00131 gchar *eurl;
00132 gchar bname[32];
00133 gint i;
00134
00135 if (!basename) {
00136 g_snprintf (bname, sizeof (bname), "%d", xform->browse_index++);
00137 basename = bname;
00138 }
00139
00140 xmms_xform_browse_add_entry (xform, basename, 0);
00141 eurl = xmms_medialib_url_encode (url);
00142 s = g_string_new (eurl);
00143
00144 for (i = 0; i < nargs; i++) {
00145 g_string_append_c (s, i == 0 ? '?' : '&');
00146 g_string_append (s, args[i]);
00147 }
00148
00149 xmms_xform_browse_add_entry_property_str (xform, "realpath", s->str);
00150
00151 g_free (eurl);
00152 g_string_free (s, TRUE);
00153 }
00154
00155 void
00156 xmms_xform_browse_add_symlink (xmms_xform_t *xform, const gchar *basename,
00157 const gchar *url)
00158 {
00159 xmms_xform_browse_add_symlink_args (xform, basename, url, 0, NULL);
00160 }
00161
00162 void
00163 xmms_xform_browse_add_entry_property (xmms_xform_t *xform, const gchar *key,
00164 xmmsv_t *val)
00165 {
00166 g_return_if_fail (xform);
00167 g_return_if_fail (xform->browse_dict);
00168 g_return_if_fail (key);
00169 g_return_if_fail (val);
00170
00171 xmmsv_dict_set (xform->browse_dict, key, val);
00172 }
00173
00174 void
00175 xmms_xform_browse_add_entry (xmms_xform_t *xform, const gchar *filename,
00176 guint32 flags)
00177 {
00178 xmmsv_t *val;
00179 const gchar *url;
00180 gchar *efile, *eurl, *t;
00181 gint l, isdir;
00182
00183 g_return_if_fail (filename);
00184
00185 t = strchr (filename, '/');
00186 g_return_if_fail (!t);
00187
00188 url = xmms_xform_get_url (xform);
00189 g_return_if_fail (url);
00190
00191 xform->browse_dict = xmmsv_new_dict ();
00192
00193 eurl = xmms_medialib_url_encode (url);
00194 efile = xmms_medialib_url_encode (filename);
00195
00196
00197
00198 l = strlen (url);
00199 if (l && url[l - 1] == '/') {
00200 t = g_strdup_printf ("%s%s", eurl, efile);
00201 } else {
00202 t = g_strdup_printf ("%s/%s", eurl, efile);
00203 }
00204
00205 isdir = !!(flags & XMMS_XFORM_BROWSE_FLAG_DIR);
00206 xmms_xform_browse_add_entry_property_str (xform, "path", t);
00207 xmms_xform_browse_add_entry_property_int (xform, "isdir", isdir);
00208
00209 val = xform->browse_dict;
00210 xform->browse_list = g_list_prepend (xform->browse_list, val);
00211
00212 g_free (t);
00213 g_free (efile);
00214 g_free (eurl);
00215 }
00216
00217 static gint
00218 xmms_browse_list_sortfunc (gconstpointer a, gconstpointer b)
00219 {
00220 int r1, r2;
00221 xmmsv_t *val1, *val2, *tmp1, *tmp2;
00222 const gchar *s1, *s2;
00223
00224 val1 = (xmmsv_t *) a;
00225 val2 = (xmmsv_t *) b;
00226
00227 g_return_val_if_fail (xmmsv_get_type (val1) == XMMSV_TYPE_DICT, 0);
00228 g_return_val_if_fail (xmmsv_get_type (val2) == XMMSV_TYPE_DICT, 0);
00229
00230 r1 = xmmsv_dict_get (val1, "intsort", &tmp1);
00231 r2 = xmmsv_dict_get (val2, "intsort", &tmp2);
00232
00233 if (r1 && r2) {
00234 gint i1, i2;
00235
00236 if (!xmmsv_get_int (tmp1, &i1))
00237 return 0;
00238 if (!xmmsv_get_int (tmp2, &i2))
00239 return 0;
00240 return i1 > i2;
00241 }
00242
00243 if (!xmmsv_dict_get (val1, "path", &tmp1))
00244 return 0;
00245 if (!xmmsv_dict_get (val2, "path", &tmp2))
00246 return 0;
00247
00248 if (!xmmsv_get_string (tmp1, &s1))
00249 return 0;
00250 if (!xmmsv_get_string (tmp2, &s2))
00251 return 0;
00252
00253 return xmms_natcmp (s1, s2);
00254 }
00255
00256 GList *
00257 xmms_xform_browse_method (xmms_xform_t *xform, const gchar *url,
00258 xmms_error_t *error)
00259 {
00260 GList *list = NULL;
00261
00262 if (xmms_xform_plugin_can_browse (xform->plugin)) {
00263 if (!xmms_xform_plugin_browse (xform->plugin, xform, url, error)) {
00264 return NULL;
00265 }
00266 list = xform->browse_list;
00267 xform->browse_list = NULL;
00268 list = g_list_sort (list, xmms_browse_list_sortfunc);
00269 } else {
00270 xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
00271 }
00272
00273 return list;
00274 }
00275
00276 GList *
00277 xmms_xform_browse (const gchar *url, xmms_error_t *error)
00278 {
00279 GList *list = NULL;
00280 gchar *durl;
00281 xmms_xform_t *xform = NULL;
00282 xmms_xform_t *xform2 = NULL;
00283
00284 xform = xmms_xform_new (NULL, NULL, 0, NULL);
00285
00286 durl = g_strdup (url);
00287 xmms_medialib_decode_url (durl);
00288 XMMS_DBG ("url = %s", durl);
00289
00290 xmms_xform_outdata_type_add (xform,
00291 XMMS_STREAM_TYPE_MIMETYPE,
00292 "application/x-url",
00293 XMMS_STREAM_TYPE_URL,
00294 durl,
00295 XMMS_STREAM_TYPE_END);
00296
00297 xform2 = xmms_xform_find (xform, 0, NULL);
00298 if (xform2) {
00299 XMMS_DBG ("found xform %s", xmms_xform_shortname (xform2));
00300 } else {
00301 xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
00302 xmms_object_unref (xform);
00303 g_free (durl);
00304 return NULL;
00305 }
00306
00307 list = xmms_xform_browse_method (xform2, durl, error);
00308
00309 xmms_object_unref (xform);
00310 xmms_object_unref (xform2);
00311
00312 g_free (durl);
00313
00314 return list;
00315 }
00316
00317 static GList *
00318 xmms_xform_client_browse (xmms_xform_object_t *obj, const gchar *url,
00319 xmms_error_t *error)
00320 {
00321 return xmms_xform_browse (url, error);
00322 }
00323
00324 static void
00325 xmms_xform_object_destroy (xmms_object_t *obj)
00326 {
00327 xmms_xform_unregister_ipc_commands ();
00328 }
00329
00330 xmms_xform_object_t *
00331 xmms_xform_object_init (void)
00332 {
00333 xmms_xform_object_t *obj;
00334
00335 obj = xmms_object_new (xmms_xform_object_t, xmms_xform_object_destroy);
00336
00337 xmms_xform_register_ipc_commands (XMMS_OBJECT (obj));
00338
00339 effect_callbacks_init ();
00340
00341 return obj;
00342 }
00343
00344 static void
00345 xmms_xform_destroy (xmms_object_t *object)
00346 {
00347 xmms_xform_t *xform = (xmms_xform_t *)object;
00348
00349 XMMS_DBG ("Freeing xform '%s'", xmms_xform_shortname (xform));
00350
00351
00352 if (xform->plugin && xform->inited) {
00353 if (xmms_xform_plugin_can_destroy (xform->plugin)) {
00354 xmms_xform_plugin_destroy (xform->plugin, xform);
00355 }
00356 }
00357
00358 g_hash_table_destroy (xform->metadata);
00359
00360 g_hash_table_destroy (xform->privdata);
00361 g_queue_free (xform->hotspots);
00362
00363 g_free (xform->buffer);
00364
00365 xmms_object_unref (xform->out_type);
00366 xmms_object_unref (xform->plugin);
00367
00368 if (xform->prev) {
00369 xmms_object_unref (xform->prev);
00370 }
00371
00372 }
00373
00374 xmms_xform_t *
00375 xmms_xform_new (xmms_xform_plugin_t *plugin, xmms_xform_t *prev,
00376 xmms_medialib_entry_t entry, GList *goal_hints)
00377 {
00378 xmms_xform_t *xform;
00379
00380 xform = xmms_object_new (xmms_xform_t, xmms_xform_destroy);
00381
00382 xmms_object_ref (plugin);
00383 xform->plugin = plugin;
00384 xform->entry = entry;
00385 xform->goal_hints = goal_hints;
00386 xform->lr.bufend = &xform->lr.buf[0];
00387
00388 if (prev) {
00389 xmms_object_ref (prev);
00390 xform->prev = prev;
00391 }
00392
00393 xform->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
00394 g_free,
00395 (GDestroyNotify) xmmsv_unref);
00396
00397 xform->privdata = g_hash_table_new_full (g_str_hash, g_str_equal,
00398 g_free,
00399 (GDestroyNotify) xmmsv_unref);
00400 xform->hotspots = g_queue_new ();
00401
00402 if (plugin && entry) {
00403 if (!xmms_xform_plugin_init (xform->plugin, xform)) {
00404 xmms_object_unref (xform);
00405 return NULL;
00406 }
00407 xform->inited = TRUE;
00408 g_return_val_if_fail (xform->out_type, NULL);
00409 }
00410
00411 xform->buffer = g_malloc (READ_CHUNK);
00412 xform->buffersize = READ_CHUNK;
00413
00414 return xform;
00415 }
00416
00417 xmms_medialib_entry_t
00418 xmms_xform_entry_get (xmms_xform_t *xform)
00419 {
00420 return xform->entry;
00421 }
00422
00423 gpointer
00424 xmms_xform_private_data_get (xmms_xform_t *xform)
00425 {
00426 return xform->priv;
00427 }
00428
00429 void
00430 xmms_xform_private_data_set (xmms_xform_t *xform, gpointer data)
00431 {
00432 xform->priv = data;
00433 }
00434
00435 void
00436 xmms_xform_outdata_type_add (xmms_xform_t *xform, ...)
00437 {
00438 va_list ap;
00439 va_start (ap, xform);
00440 xform->out_type = xmms_stream_type_parse (ap);
00441 va_end (ap);
00442 }
00443
00444 void
00445 xmms_xform_outdata_type_set (xmms_xform_t *xform, xmms_stream_type_t *type)
00446 {
00447 xmms_object_ref (type);
00448 xform->out_type = type;
00449 }
00450
00451 void
00452 xmms_xform_outdata_type_copy (xmms_xform_t *xform)
00453 {
00454 xmms_object_ref (xform->prev->out_type);
00455 xform->out_type = xform->prev->out_type;
00456 }
00457
00458 const char *
00459 xmms_xform_indata_find_str (xmms_xform_t *xform, xmms_stream_type_key_t key)
00460 {
00461 const gchar *r;
00462 r = xmms_stream_type_get_str (xform->prev->out_type, key);
00463 if (r) {
00464 return r;
00465 } else if (xform->prev) {
00466 return xmms_xform_indata_find_str (xform->prev, key);
00467 }
00468 return NULL;
00469 }
00470
00471 const char *
00472 xmms_xform_indata_get_str (xmms_xform_t *xform, xmms_stream_type_key_t key)
00473 {
00474 return xmms_stream_type_get_str (xform->prev->out_type, key);
00475 }
00476
00477 gint
00478 xmms_xform_indata_get_int (xmms_xform_t *xform, xmms_stream_type_key_t key)
00479 {
00480 return xmms_stream_type_get_int (xform->prev->out_type, key);
00481 }
00482
00483 xmms_stream_type_t *
00484 xmms_xform_outtype_get (xmms_xform_t *xform)
00485 {
00486 return xform->out_type;
00487 }
00488
00489 xmms_stream_type_t *
00490 xmms_xform_intype_get (xmms_xform_t *xform)
00491 {
00492 return xmms_xform_outtype_get (xform->prev);
00493 }
00494
00495
00496
00497 const char *
00498 xmms_xform_outtype_get_str (xmms_xform_t *xform, xmms_stream_type_key_t key)
00499 {
00500 return xmms_stream_type_get_str (xform->out_type, key);
00501 }
00502
00503 gint
00504 xmms_xform_outtype_get_int (xmms_xform_t *xform, xmms_stream_type_key_t key)
00505 {
00506 return xmms_stream_type_get_int (xform->out_type, key);
00507 }
00508
00509
00510 void
00511 xmms_xform_metadata_set_int (xmms_xform_t *xform, const char *key, int val)
00512 {
00513 XMMS_DBG ("Setting '%s' to %d", key, val);
00514 g_hash_table_insert (xform->metadata, g_strdup (key),
00515 xmmsv_new_int (val));
00516 xform->metadata_changed = TRUE;
00517 }
00518
00519 void
00520 xmms_xform_metadata_set_str (xmms_xform_t *xform, const char *key,
00521 const char *val)
00522 {
00523 const char *old;
00524
00525 if (!g_utf8_validate (val, -1, NULL)) {
00526 xmms_log_error ("xform '%s' tried to set property '%s' to a NON UTF-8 string!", xmms_xform_shortname (xform), key);
00527 return;
00528 }
00529
00530 if (xmms_xform_metadata_get_str (xform, key, &old)) {
00531 if (strcmp (old, val) == 0) {
00532 return;
00533 }
00534 }
00535
00536 g_hash_table_insert (xform->metadata, g_strdup (key),
00537 xmmsv_new_string (val));
00538
00539 xform->metadata_changed = TRUE;
00540 }
00541
00542 static const xmmsv_t *
00543 xmms_xform_metadata_get_val (xmms_xform_t *xform, const char *key)
00544 {
00545 xmmsv_t *val = NULL;
00546
00547 for (; xform; xform = xform->prev) {
00548 val = g_hash_table_lookup (xform->metadata, key);
00549 if (val) {
00550 break;
00551 }
00552 }
00553
00554 return val;
00555 }
00556
00557 gboolean
00558 xmms_xform_metadata_has_val (xmms_xform_t *xform, const gchar *key)
00559 {
00560 return !!xmms_xform_metadata_get_val (xform, key);
00561 }
00562
00563 gboolean
00564 xmms_xform_metadata_get_int (xmms_xform_t *xform, const char *key,
00565 gint32 *val)
00566 {
00567 const xmmsv_t *obj;
00568 gboolean ret = FALSE;
00569
00570 obj = xmms_xform_metadata_get_val (xform, key);
00571 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) {
00572 xmmsv_get_int (obj, val);
00573 ret = TRUE;
00574 }
00575
00576 return ret;
00577 }
00578
00579 gboolean
00580 xmms_xform_metadata_get_str (xmms_xform_t *xform, const char *key,
00581 const gchar **val)
00582 {
00583 const xmmsv_t *obj;
00584 gboolean ret = FALSE;
00585
00586 obj = xmms_xform_metadata_get_val (xform, key);
00587 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) {
00588 xmmsv_get_string (obj, val);
00589 ret = TRUE;
00590 }
00591
00592 return ret;
00593 }
00594
00595 typedef struct {
00596 xmms_medialib_session_t *session;
00597 xmms_medialib_entry_t entry;
00598 guint32 source;
00599 } metadata_festate_t;
00600
00601 static void
00602 add_metadatum (gpointer _key, gpointer _value, gpointer user_data)
00603 {
00604 xmmsv_t *value = (xmmsv_t *) _value;
00605 gchar *key = (gchar *) _key;
00606 metadata_festate_t *st = (metadata_festate_t *) user_data;
00607
00608 if (xmmsv_get_type (value) == XMMSV_TYPE_STRING) {
00609 const gchar *s;
00610 xmmsv_get_string (value, &s);
00611 xmms_medialib_entry_property_set_str_source (st->session,
00612 st->entry,
00613 key,
00614 s,
00615 st->source);
00616 } else if (xmmsv_get_type (value) == XMMSV_TYPE_INT32) {
00617 gint i;
00618 xmmsv_get_int (value, &i);
00619 xmms_medialib_entry_property_set_int_source (st->session,
00620 st->entry,
00621 key,
00622 i,
00623 st->source);
00624 } else {
00625 XMMS_DBG ("Unknown type?!?");
00626 }
00627 }
00628
00629 static void
00630 xmms_xform_metadata_collect_one (xmms_xform_t *xform, metadata_festate_t *info)
00631 {
00632 gchar src[XMMS_PLUGIN_SHORTNAME_MAX_LEN + 8];
00633
00634 XMMS_DBG ("Collecting metadata from %s", xmms_xform_shortname (xform));
00635
00636 g_snprintf (src, sizeof (src), "plugin/%s",
00637 xmms_xform_shortname (xform));
00638
00639 info->source = xmms_medialib_source_to_id (info->session, src);
00640 g_hash_table_foreach (xform->metadata, add_metadatum, info);
00641
00642 xform->metadata_changed = FALSE;
00643 }
00644
00645 static void
00646 xmms_xform_metadata_collect_r (xmms_xform_t *xform, metadata_festate_t *info,
00647 GString *namestr)
00648 {
00649 if (xform->prev) {
00650 xmms_xform_metadata_collect_r (xform->prev, info, namestr);
00651 }
00652
00653 if (xform->plugin) {
00654 if (namestr->len) {
00655 g_string_append_c (namestr, ':');
00656 }
00657 g_string_append (namestr, xmms_xform_shortname (xform));
00658 }
00659
00660 if (xform->metadata_changed) {
00661 xmms_xform_metadata_collect_one (xform, info);
00662 }
00663
00664 xform->metadata_collected = TRUE;
00665 }
00666
00667 static void
00668 xmms_xform_metadata_collect (xmms_xform_t *start, GString *namestr, gboolean rehashing)
00669 {
00670 metadata_festate_t info;
00671 gint times_played;
00672 gint last_started;
00673 GTimeVal now;
00674
00675 info.entry = start->entry;
00676 info.session = xmms_medialib_begin_write ();
00677
00678 times_played = xmms_medialib_entry_property_get_int (info.session,
00679 info.entry,
00680 XMMS_MEDIALIB_ENTRY_PROPERTY_TIMESPLAYED);
00681
00682
00683
00684
00685 if (times_played < 0) {
00686 times_played = 0;
00687 }
00688
00689 last_started = xmms_medialib_entry_property_get_int (info.session,
00690 info.entry,
00691 XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED);
00692
00693 xmms_medialib_entry_cleanup (info.session, info.entry);
00694
00695 xmms_xform_metadata_collect_r (start, &info, namestr);
00696
00697 xmms_medialib_entry_property_set_str (info.session, info.entry,
00698 XMMS_MEDIALIB_ENTRY_PROPERTY_CHAIN,
00699 namestr->str);
00700
00701 xmms_medialib_entry_property_set_int (info.session, info.entry,
00702 XMMS_MEDIALIB_ENTRY_PROPERTY_TIMESPLAYED,
00703 times_played + (rehashing ? 0 : 1));
00704
00705 if (!rehashing || (rehashing && last_started)) {
00706 g_get_current_time (&now);
00707
00708 xmms_medialib_entry_property_set_int (info.session, info.entry,
00709 XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED,
00710 (rehashing ? last_started : now.tv_sec));
00711 }
00712
00713 xmms_medialib_entry_status_set (info.session, info.entry,
00714 XMMS_MEDIALIB_ENTRY_STATUS_OK);
00715
00716 xmms_medialib_end (info.session);
00717 xmms_medialib_entry_send_update (info.entry);
00718 }
00719
00720 static void
00721 xmms_xform_metadata_update (xmms_xform_t *xform)
00722 {
00723 metadata_festate_t info;
00724
00725 info.entry = xform->entry;
00726 info.session = xmms_medialib_begin_write ();
00727
00728 xmms_xform_metadata_collect_one (xform, &info);
00729
00730 xmms_medialib_end (info.session);
00731 xmms_medialib_entry_send_update (info.entry);
00732 }
00733
00734 static void
00735 xmms_xform_auxdata_set_val (xmms_xform_t *xform, char *key, xmmsv_t *val)
00736 {
00737 xmms_xform_hotspot_t *hs;
00738
00739 hs = g_new0 (xmms_xform_hotspot_t, 1);
00740 hs->pos = xform->buffered;
00741 hs->key = key;
00742 hs->obj = val;
00743
00744 g_queue_push_tail (xform->hotspots, hs);
00745 }
00746
00747 void
00748 xmms_xform_auxdata_barrier (xmms_xform_t *xform)
00749 {
00750 xmmsv_t *val = xmmsv_new_none ();
00751 xmms_xform_auxdata_set_val (xform, NULL, val);
00752 }
00753
00754 void
00755 xmms_xform_auxdata_set_int (xmms_xform_t *xform, const char *key, int intval)
00756 {
00757 xmmsv_t *val = xmmsv_new_int (intval);
00758 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
00759 }
00760
00761 void
00762 xmms_xform_auxdata_set_str (xmms_xform_t *xform, const gchar *key,
00763 const gchar *strval)
00764 {
00765 xmmsv_t *val;
00766 const char *old;
00767
00768 if (xmms_xform_auxdata_get_str (xform, key, &old)) {
00769 if (strcmp (old, strval) == 0) {
00770 return;
00771 }
00772 }
00773
00774 val = xmmsv_new_string (strval);
00775 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
00776 }
00777
00778 void
00779 xmms_xform_auxdata_set_bin (xmms_xform_t *xform, const gchar *key,
00780 gpointer data, gssize len)
00781 {
00782 xmmsv_t *val;
00783
00784 val = xmmsv_new_bin (data, len);
00785 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
00786 }
00787
00788 static const xmmsv_t *
00789 xmms_xform_auxdata_get_val (xmms_xform_t *xform, const gchar *key)
00790 {
00791 guint i;
00792 xmms_xform_hotspot_t *hs;
00793 xmmsv_t *val = NULL;
00794
00795
00796 xform = xform->prev;
00797
00798
00799 for (i=0; (hs = g_queue_peek_nth (xform->hotspots, i)) != NULL; i++) {
00800 if (hs->pos != 0) {
00801 break;
00802 } else if (hs->key && !strcmp (key, hs->key)) {
00803 val = hs->obj;
00804 }
00805 }
00806
00807 if (!val) {
00808 val = g_hash_table_lookup (xform->privdata, key);
00809 }
00810
00811 return val;
00812 }
00813
00814 gboolean
00815 xmms_xform_auxdata_has_val (xmms_xform_t *xform, const gchar *key)
00816 {
00817 return !!xmms_xform_auxdata_get_val (xform, key);
00818 }
00819
00820 gboolean
00821 xmms_xform_auxdata_get_int (xmms_xform_t *xform, const gchar *key, gint32 *val)
00822 {
00823 const xmmsv_t *obj;
00824
00825 obj = xmms_xform_auxdata_get_val (xform, key);
00826 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) {
00827 xmmsv_get_int (obj, val);
00828 return TRUE;
00829 }
00830
00831 return FALSE;
00832 }
00833
00834 gboolean
00835 xmms_xform_auxdata_get_str (xmms_xform_t *xform, const gchar *key,
00836 const gchar **val)
00837 {
00838 const xmmsv_t *obj;
00839
00840 obj = xmms_xform_auxdata_get_val (xform, key);
00841 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) {
00842 xmmsv_get_string (obj, val);
00843 return TRUE;
00844 }
00845
00846 return FALSE;
00847 }
00848
00849 gboolean
00850 xmms_xform_auxdata_get_bin (xmms_xform_t *xform, const gchar *key,
00851 const guchar **data, gsize *datalen)
00852 {
00853 const xmmsv_t *obj;
00854
00855 obj = xmms_xform_auxdata_get_val (xform, key);
00856 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_BIN) {
00857 xmmsv_get_bin (obj, data, datalen);
00858 return TRUE;
00859 }
00860
00861 return FALSE;
00862 }
00863
00864 const char *
00865 xmms_xform_shortname (xmms_xform_t *xform)
00866 {
00867 return (xform->plugin)
00868 ? xmms_plugin_shortname_get ((xmms_plugin_t *) xform->plugin)
00869 : "unknown";
00870 }
00871
00872 static gint
00873 xmms_xform_this_peek (xmms_xform_t *xform, gpointer buf, gint siz,
00874 xmms_error_t *err)
00875 {
00876 while (xform->buffered < siz) {
00877 gint res;
00878
00879 if (xform->buffered + READ_CHUNK > xform->buffersize) {
00880 xform->buffersize *= 2;
00881 xform->buffer = g_realloc (xform->buffer, xform->buffersize);
00882 }
00883
00884 res = xmms_xform_plugin_read (xform->plugin, xform,
00885 &xform->buffer[xform->buffered],
00886 READ_CHUNK, err);
00887
00888 if (res < -1) {
00889 XMMS_DBG ("Read method of %s returned bad value (%d) - BUG IN PLUGIN",
00890 xmms_xform_shortname (xform), res);
00891 res = -1;
00892 }
00893
00894 if (res == 0) {
00895 xform->eos = TRUE;
00896 break;
00897 } else if (res == -1) {
00898 xform->error = TRUE;
00899 return -1;
00900 } else {
00901 xform->buffered += res;
00902 }
00903 }
00904
00905
00906 siz = MIN (siz, xform->buffered);
00907 memcpy (buf, xform->buffer, siz);
00908 return siz;
00909 }
00910
00911 static void
00912 xmms_xform_hotspot_callback (gpointer data, gpointer user_data)
00913 {
00914 xmms_xform_hotspot_t *hs = data;
00915 gint *read = user_data;
00916
00917 hs->pos -= *read;
00918 }
00919
00920 static gint
00921 xmms_xform_hotspots_update (xmms_xform_t *xform)
00922 {
00923 xmms_xform_hotspot_t *hs;
00924 gint ret = -1;
00925
00926 hs = g_queue_peek_head (xform->hotspots);
00927 while (hs != NULL && hs->pos == 0) {
00928 g_queue_pop_head (xform->hotspots);
00929 if (hs->key) {
00930 g_hash_table_insert (xform->privdata, hs->key, hs->obj);
00931 }
00932 hs = g_queue_peek_head (xform->hotspots);
00933 }
00934
00935 if (hs != NULL) {
00936 ret = hs->pos;
00937 }
00938
00939 return ret;
00940 }
00941
00942 gint
00943 xmms_xform_this_read (xmms_xform_t *xform, gpointer buf, gint siz,
00944 xmms_error_t *err)
00945 {
00946 gint read = 0;
00947 gint nexths;
00948
00949 if (xform->error) {
00950 xmms_error_set (err, XMMS_ERROR_GENERIC, "Read on errored xform");
00951 return -1;
00952 }
00953
00954
00955 nexths = xmms_xform_hotspots_update (xform);
00956 if (nexths >= 0) {
00957 siz = MIN (siz, nexths);
00958 }
00959
00960 if (xform->buffered) {
00961 read = MIN (siz, xform->buffered);
00962 memcpy (buf, xform->buffer, read);
00963 xform->buffered -= read;
00964
00965
00966 g_queue_foreach (xform->hotspots, &xmms_xform_hotspot_callback, &read);
00967
00968 if (xform->buffered) {
00969
00970
00971 memmove (xform->buffer, &xform->buffer[read], xform->buffered);
00972 }
00973 }
00974
00975 if (xform->eos) {
00976 return read;
00977 }
00978
00979 while (read < siz) {
00980 gint res;
00981
00982 res = xmms_xform_plugin_read (xform->plugin, xform, buf + read, siz - read, err);
00983 if (xform->metadata_collected && xform->metadata_changed)
00984 xmms_xform_metadata_update (xform);
00985
00986 if (res < -1) {
00987 XMMS_DBG ("Read method of %s returned bad value (%d) - BUG IN PLUGIN", xmms_xform_shortname (xform), res);
00988 res = -1;
00989 }
00990
00991 if (res == 0) {
00992 xform->eos = TRUE;
00993 break;
00994 } else if (res == -1) {
00995 xform->error = TRUE;
00996 return -1;
00997 } else {
00998 if (read == 0)
00999 xmms_xform_hotspots_update (xform);
01000
01001 if (!g_queue_is_empty (xform->hotspots)) {
01002 if (xform->buffered + res > xform->buffersize) {
01003 xform->buffersize = MAX (xform->buffersize * 2,
01004 xform->buffersize + res);
01005 xform->buffer = g_realloc (xform->buffer,
01006 xform->buffersize);
01007 }
01008
01009 g_memmove (xform->buffer + xform->buffered, buf + read, res);
01010 xform->buffered += res;
01011 break;
01012 }
01013 read += res;
01014 }
01015 }
01016
01017 return read;
01018 }
01019
01020 gint64
01021 xmms_xform_this_seek (xmms_xform_t *xform, gint64 offset,
01022 xmms_xform_seek_mode_t whence, xmms_error_t *err)
01023 {
01024 gint64 res;
01025
01026 if (xform->error) {
01027 xmms_error_set (err, XMMS_ERROR_GENERIC, "Seek on errored xform");
01028 return -1;
01029 }
01030
01031 if (!xmms_xform_plugin_can_seek (xform->plugin)) {
01032 XMMS_DBG ("Seek not implemented in '%s'", xmms_xform_shortname (xform));
01033 xmms_error_set (err, XMMS_ERROR_GENERIC, "Seek not implemented");
01034 return -1;
01035 }
01036
01037 if (xform->buffered && whence == XMMS_XFORM_SEEK_CUR) {
01038 offset -= xform->buffered;
01039 }
01040
01041 res = xmms_xform_plugin_seek (xform->plugin, xform, offset, whence, err);
01042 if (res != -1) {
01043 xmms_xform_hotspot_t *hs;
01044
01045 xform->eos = FALSE;
01046 xform->buffered = 0;
01047
01048
01049 while ((hs = g_queue_pop_head (xform->hotspots)) != NULL) {
01050 g_free (hs->key);
01051 xmmsv_unref (hs->obj);
01052 g_free (hs);
01053 }
01054 }
01055
01056 return res;
01057 }
01058
01059 gint
01060 xmms_xform_peek (xmms_xform_t *xform, gpointer buf, gint siz,
01061 xmms_error_t *err)
01062 {
01063 g_return_val_if_fail (xform->prev, -1);
01064 return xmms_xform_this_peek (xform->prev, buf, siz, err);
01065 }
01066
01067 gchar *
01068 xmms_xform_read_line (xmms_xform_t *xform, gchar *line, xmms_error_t *err)
01069 {
01070 gchar *p;
01071
01072 g_return_val_if_fail (xform, NULL);
01073 g_return_val_if_fail (line, NULL);
01074
01075 p = strchr (xform->lr.buf, '\n');
01076
01077 if (!p) {
01078 gint l, r;
01079
01080 l = (XMMS_XFORM_MAX_LINE_SIZE - 1) - (xform->lr.bufend - xform->lr.buf);
01081 if (l) {
01082 r = xmms_xform_read (xform, xform->lr.bufend, l, err);
01083 if (r < 0) {
01084 return NULL;
01085 }
01086 xform->lr.bufend += r;
01087 }
01088 if (xform->lr.bufend <= xform->lr.buf)
01089 return NULL;
01090
01091 *(xform->lr.bufend) = '\0';
01092 p = strchr (xform->lr.buf, '\n');
01093 if (!p) {
01094 p = xform->lr.bufend;
01095 }
01096 }
01097
01098 if (p > xform->lr.buf && *(p-1) == '\r') {
01099 *(p-1) = '\0';
01100 } else {
01101 *p = '\0';
01102 }
01103
01104 strcpy (line, xform->lr.buf);
01105 memmove (xform->lr.buf, p + 1, xform->lr.bufend - p);
01106 xform->lr.bufend -= (p - xform->lr.buf) + 1;
01107 *xform->lr.bufend = '\0';
01108
01109 return line;
01110 }
01111
01112 gint
01113 xmms_xform_read (xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
01114 {
01115 g_return_val_if_fail (xform->prev, -1);
01116 return xmms_xform_this_read (xform->prev, buf, siz, err);
01117 }
01118
01119 gint64
01120 xmms_xform_seek (xmms_xform_t *xform, gint64 offset,
01121 xmms_xform_seek_mode_t whence, xmms_error_t *err)
01122 {
01123 g_return_val_if_fail (xform->prev, -1);
01124 return xmms_xform_this_seek (xform->prev, offset, whence, err);
01125 }
01126
01127 const gchar *
01128 xmms_xform_get_url (xmms_xform_t *xform)
01129 {
01130 const gchar *url = NULL;
01131 xmms_xform_t *x;
01132 x = xform;
01133
01134 while (!url && x) {
01135 url = xmms_xform_indata_get_str (x, XMMS_STREAM_TYPE_URL);
01136 x = x->prev;
01137 }
01138
01139 return url;
01140 }
01141
01142
01143 typedef struct match_state_St {
01144 xmms_xform_plugin_t *match;
01145 xmms_stream_type_t *out_type;
01146 gint priority;
01147 } match_state_t;
01148
01149 static gboolean
01150 xmms_xform_match (xmms_plugin_t *plugin, gpointer user_data)
01151 {
01152 xmms_xform_plugin_t *xform_plugin = (xmms_xform_plugin_t *) plugin;
01153 match_state_t *state = (match_state_t *) user_data;
01154 gint priority = 0;
01155
01156 g_assert (plugin->type == XMMS_PLUGIN_TYPE_XFORM);
01157
01158 XMMS_DBG ("Trying plugin '%s'", xmms_plugin_shortname_get (plugin));
01159 if (!xmms_xform_plugin_supports (xform_plugin, state->out_type, &priority)) {
01160 return TRUE;
01161 }
01162
01163 XMMS_DBG ("Plugin '%s' matched (priority %d)",
01164 xmms_plugin_shortname_get (plugin), priority);
01165
01166 if (priority > state->priority) {
01167 if (state->match) {
01168 xmms_plugin_t *previous_plugin = (xmms_plugin_t *) state->match;
01169 XMMS_DBG ("Using plugin '%s' (priority %d) instead of '%s' (priority %d)",
01170 xmms_plugin_shortname_get (plugin), priority,
01171 xmms_plugin_shortname_get (previous_plugin),
01172 state->priority);
01173 }
01174
01175 state->match = xform_plugin;
01176 state->priority = priority;
01177 }
01178
01179 return TRUE;
01180 }
01181
01182 xmms_xform_t *
01183 xmms_xform_find (xmms_xform_t *prev, xmms_medialib_entry_t entry,
01184 GList *goal_hints)
01185 {
01186 match_state_t state;
01187 xmms_xform_t *xform = NULL;
01188
01189 state.out_type = prev->out_type;
01190 state.match = NULL;
01191 state.priority = -1;
01192
01193 xmms_plugin_foreach (XMMS_PLUGIN_TYPE_XFORM, xmms_xform_match, &state);
01194
01195 if (state.match) {
01196 xform = xmms_xform_new (state.match, prev, entry, goal_hints);
01197 } else {
01198 XMMS_DBG ("Found no matching plugin...");
01199 }
01200
01201 return xform;
01202 }
01203
01204 gboolean
01205 xmms_xform_iseos (xmms_xform_t *xform)
01206 {
01207 gboolean ret = TRUE;
01208
01209 if (xform->prev) {
01210 ret = xform->prev->eos;
01211 }
01212
01213 return ret;
01214 }
01215
01216 const xmms_stream_type_t *
01217 xmms_xform_get_out_stream_type (xmms_xform_t *xform)
01218 {
01219 return xform->out_type;
01220 }
01221
01222 const GList *
01223 xmms_xform_goal_hints_get (xmms_xform_t *xform)
01224 {
01225 return xform->goal_hints;
01226 }
01227
01228
01229 static gboolean
01230 has_goalformat (xmms_xform_t *xform, GList *goal_formats)
01231 {
01232 const xmms_stream_type_t *current;
01233 gboolean ret = FALSE;
01234 GList *n;
01235
01236 current = xmms_xform_get_out_stream_type (xform);
01237
01238 for (n = goal_formats; n; n = g_list_next (n)) {
01239 xmms_stream_type_t *goal_type = n->data;
01240 if (xmms_stream_type_match (goal_type, current)) {
01241 ret = TRUE;
01242 break;
01243 }
01244
01245 }
01246
01247 if (!ret) {
01248 XMMS_DBG ("Not in one of %d goal-types", g_list_length (goal_formats));
01249 }
01250
01251 return ret;
01252 }
01253
01254 static void
01255 outdata_type_metadata_collect (xmms_xform_t *xform)
01256 {
01257 gint val;
01258 const char *mime;
01259 xmms_stream_type_t *type;
01260
01261 type = xform->out_type;
01262 mime = xmms_stream_type_get_str (type, XMMS_STREAM_TYPE_MIMETYPE);
01263 if (strcmp (mime, "audio/pcm") != 0) {
01264 return;
01265 }
01266
01267 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_FORMAT);
01268 if (val != -1) {
01269 const gchar *name = xmms_sample_name_get ((xmms_sample_format_t) val);
01270 xmms_xform_metadata_set_str (xform,
01271 XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLE_FMT,
01272 name);
01273 }
01274
01275 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
01276 if (val != -1) {
01277 xmms_xform_metadata_set_int (xform,
01278 XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE,
01279 val);
01280 }
01281
01282 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_CHANNELS);
01283 if (val != -1) {
01284 xmms_xform_metadata_set_int (xform,
01285 XMMS_MEDIALIB_ENTRY_PROPERTY_CHANNELS,
01286 val);
01287 }
01288 }
01289
01290 static xmms_xform_t *
01291 chain_setup (xmms_medialib_entry_t entry, const gchar *url, GList *goal_formats)
01292 {
01293 xmms_xform_t *xform, *last;
01294 gchar *durl, *args;
01295
01296 if (!entry) {
01297 entry = 1;
01298 }
01299
01300 xform = xmms_xform_new (NULL, NULL, 0, goal_formats);
01301
01302 durl = g_strdup (url);
01303
01304 args = strchr (durl, '?');
01305 if (args) {
01306 gchar **params;
01307 gint i;
01308 *args = 0;
01309 args++;
01310 xmms_medialib_decode_url (args);
01311
01312 params = g_strsplit (args, "&", 0);
01313
01314 for (i = 0; params && params[i]; i++) {
01315 gchar *v;
01316 v = strchr (params[i], '=');
01317 if (v) {
01318 *v = 0;
01319 v++;
01320 xmms_xform_metadata_set_str (xform, params[i], v);
01321 } else {
01322 xmms_xform_metadata_set_int (xform, params[i], 1);
01323 }
01324 }
01325 g_strfreev (params);
01326 }
01327 xmms_medialib_decode_url (durl);
01328
01329 xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE,
01330 "application/x-url", XMMS_STREAM_TYPE_URL,
01331 durl, XMMS_STREAM_TYPE_END);
01332
01333 g_free (durl);
01334
01335 last = xform;
01336
01337 do {
01338 xform = xmms_xform_find (last, entry, goal_formats);
01339 if (!xform) {
01340 xmms_log_error ("Couldn't set up chain for '%s' (%d)",
01341 url, entry);
01342 xmms_object_unref (last);
01343
01344 return NULL;
01345 }
01346 xmms_object_unref (last);
01347 last = xform;
01348 } while (!has_goalformat (xform, goal_formats));
01349
01350 outdata_type_metadata_collect (last);
01351
01352 return last;
01353 }
01354
01355 static void
01356 chain_finalize (xmms_xform_t *xform, xmms_medialib_entry_t entry,
01357 const gchar *url, gboolean rehashing)
01358 {
01359 GString *namestr;
01360
01361 namestr = g_string_new ("");
01362 xmms_xform_metadata_collect (xform, namestr, rehashing);
01363 xmms_log_info ("Successfully setup chain for '%s' (%d) containing %s",
01364 url, entry, namestr->str);
01365
01366 g_string_free (namestr, TRUE);
01367 }
01368
01369 static gchar *
01370 get_url_for_entry (xmms_medialib_entry_t entry)
01371 {
01372 xmms_medialib_session_t *session;
01373 gchar *url = NULL;
01374
01375 session = xmms_medialib_begin ();
01376 url = xmms_medialib_entry_property_get_str (session, entry,
01377 XMMS_MEDIALIB_ENTRY_PROPERTY_URL);
01378 xmms_medialib_end (session);
01379
01380 if (!url) {
01381 xmms_log_error ("Couldn't get url for entry (%d)", entry);
01382 }
01383
01384 return url;
01385 }
01386
01387 xmms_xform_t *
01388 xmms_xform_chain_setup (xmms_medialib_entry_t entry, GList *goal_formats,
01389 gboolean rehash)
01390 {
01391 gchar *url;
01392 xmms_xform_t *xform;
01393
01394 if (!(url = get_url_for_entry (entry))) {
01395 return NULL;
01396 }
01397
01398 xform = xmms_xform_chain_setup_url (entry, url, goal_formats, rehash);
01399 g_free (url);
01400
01401 return xform;
01402 }
01403
01404 xmms_xform_t *
01405 xmms_xform_chain_setup_url (xmms_medialib_entry_t entry, const gchar *url,
01406 GList *goal_formats, gboolean rehash)
01407 {
01408 xmms_xform_t *last;
01409 xmms_plugin_t *plugin;
01410 xmms_xform_plugin_t *xform_plugin;
01411 gboolean add_segment = FALSE;
01412 gint priority;
01413
01414 last = chain_setup (entry, url, goal_formats);
01415 if (!last) {
01416 return NULL;
01417 }
01418
01419
01420 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, "segment");
01421 xform_plugin = (xmms_xform_plugin_t *) plugin;
01422
01423
01424
01425 if (xform_plugin) {
01426 add_segment = xmms_xform_plugin_supports (xform_plugin,
01427 last->out_type,
01428 &priority);
01429 xmms_object_unref (plugin);
01430 }
01431
01432
01433 if (add_segment) {
01434 last = xmms_xform_new_effect (last, entry, goal_formats, "segment");
01435 if (!last) {
01436 return NULL;
01437 }
01438 }
01439
01440
01441 if (!rehash) {
01442 last = add_effects (last, entry, goal_formats);
01443 if (!last) {
01444 return NULL;
01445 }
01446 }
01447
01448 chain_finalize (last, entry, url, rehash);
01449 return last;
01450 }
01451
01452 xmms_config_property_t *
01453 xmms_xform_config_lookup (xmms_xform_t *xform, const gchar *path)
01454 {
01455 g_return_val_if_fail (xform->plugin, NULL);
01456
01457 return xmms_plugin_config_lookup ((xmms_plugin_t *) xform->plugin, path);
01458 }
01459
01460 static xmms_xform_t *
01461 add_effects (xmms_xform_t *last, xmms_medialib_entry_t entry,
01462 GList *goal_formats)
01463 {
01464 gint effect_no;
01465
01466 for (effect_no = 0; TRUE; effect_no++) {
01467 xmms_config_property_t *cfg;
01468 gchar key[64];
01469 const gchar *name;
01470
01471 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
01472
01473 cfg = xmms_config_lookup (key);
01474 if (!cfg) {
01475 break;
01476 }
01477
01478 name = xmms_config_property_get_string (cfg);
01479
01480 if (!name[0]) {
01481 continue;
01482 }
01483
01484 last = xmms_xform_new_effect (last, entry, goal_formats, name);
01485 }
01486
01487 return last;
01488 }
01489
01490 static xmms_xform_t *
01491 xmms_xform_new_effect (xmms_xform_t *last, xmms_medialib_entry_t entry,
01492 GList *goal_formats, const gchar *name)
01493 {
01494 xmms_plugin_t *plugin;
01495 xmms_xform_plugin_t *xform_plugin;
01496 xmms_xform_t *xform;
01497 gint priority;
01498
01499 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01500 if (!plugin) {
01501 xmms_log_error ("Couldn't find any effect named '%s'", name);
01502 return last;
01503 }
01504
01505 xform_plugin = (xmms_xform_plugin_t *) plugin;
01506 if (!xmms_xform_plugin_supports (xform_plugin, last->out_type, &priority)) {
01507 xmms_log_info ("Effect '%s' doesn't support format, skipping",
01508 xmms_plugin_shortname_get (plugin));
01509 xmms_object_unref (plugin);
01510 return last;
01511 }
01512
01513 xform = xmms_xform_new (xform_plugin, last, entry, goal_formats);
01514
01515 if (xform) {
01516 xmms_object_unref (last);
01517 last = xform;
01518 } else {
01519 xmms_log_info ("Effect '%s' failed to initialize, skipping",
01520 xmms_plugin_shortname_get (plugin));
01521 }
01522 xmms_xform_plugin_config_property_register (xform_plugin,
01523 "enabled", "0",
01524 NULL, NULL);
01525 xmms_object_unref (plugin);
01526 return last;
01527 }
01528
01529 static void
01530 update_effect_properties (xmms_object_t *object, xmmsv_t *data,
01531 gpointer userdata)
01532 {
01533 gint effect_no = GPOINTER_TO_INT (userdata);
01534 const gchar *name;
01535
01536 xmms_config_property_t *cfg;
01537 xmms_xform_plugin_t *xform_plugin;
01538 xmms_plugin_t *plugin;
01539 gchar key[64];
01540
01541 name = xmms_config_property_get_string ((xmms_config_property_t *) object);
01542
01543 if (name[0]) {
01544 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01545 if (!plugin) {
01546 xmms_log_error ("Couldn't find any effect named '%s'", name);
01547 } else {
01548 xform_plugin = (xmms_xform_plugin_t *) plugin;
01549 xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
01550 "1", NULL, NULL);
01551 xmms_object_unref (plugin);
01552 }
01553
01554
01555 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no + 1);
01556
01557 cfg = xmms_config_lookup (key);
01558 if (!cfg) {
01559 xmms_config_property_register (key, "", update_effect_properties,
01560 GINT_TO_POINTER (effect_no + 1));
01561 }
01562 }
01563 }
01564
01565 static void
01566 effect_callbacks_init (void)
01567 {
01568 gint effect_no;
01569
01570 xmms_config_property_t *cfg;
01571 xmms_xform_plugin_t *xform_plugin;
01572 xmms_plugin_t *plugin;
01573 gchar key[64];
01574 const gchar *name;
01575
01576 for (effect_no = 0; ; effect_no++) {
01577 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
01578
01579 cfg = xmms_config_lookup (key);
01580 if (!cfg) {
01581 break;
01582 }
01583 xmms_config_property_callback_set (cfg, update_effect_properties,
01584 GINT_TO_POINTER (effect_no));
01585
01586 name = xmms_config_property_get_string (cfg);
01587 if (!name[0]) {
01588 continue;
01589 }
01590
01591 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01592 if (!plugin) {
01593 xmms_log_error ("Couldn't find any effect named '%s'", name);
01594 continue;
01595 }
01596
01597 xform_plugin = (xmms_xform_plugin_t *) plugin;
01598 xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
01599 "1", NULL, NULL);
01600
01601 xmms_object_unref (plugin);
01602 }
01603
01604
01605
01606 if ((!effect_no) || name[0]) {
01607 xmms_config_property_register (key, "", update_effect_properties,
01608 GINT_TO_POINTER (effect_no));
01609 }
01610 }
01611