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 "xmms/xmms_ipc.h"
00030 #include "xmms/xmms_log.h"
00031 #include "xmms/xmms_object.h"
00032
00033 struct xmms_xform_object_St {
00034 xmms_object_t obj;
00035 };
00036
00037 struct xmms_xform_St {
00038 xmms_object_t obj;
00039 struct xmms_xform_St *prev;
00040
00041 const xmms_xform_plugin_t *plugin;
00042 xmms_medialib_entry_t entry;
00043
00044 gboolean inited;
00045
00046 void *priv;
00047
00048 xmms_stream_type_t *out_type;
00049
00050 GList *goal_hints;
00051
00052 gboolean eos;
00053 gboolean error;
00054
00055 char *buffer;
00056 gint buffered;
00057 gint buffersize;
00058
00059 gboolean metadata_collected;
00060
00061 gboolean metadata_changed;
00062 GHashTable *metadata;
00063
00064 GHashTable *privdata;
00065 GQueue *hotspots;
00066
00067 GList *browse_list;
00068 xmmsv_t *browse_dict;
00069 gint browse_index;
00070
00071
00072 struct {
00073 gchar buf[XMMS_XFORM_MAX_LINE_SIZE];
00074 gchar *bufend;
00075 } lr;
00076 };
00077
00078 typedef struct xmms_xform_hotspot_St {
00079 guint pos;
00080 gchar *key;
00081 xmmsv_t *obj;
00082 } xmms_xform_hotspot_t;
00083
00084 #define READ_CHUNK 4096
00085
00086 struct xmms_xform_plugin_St {
00087 xmms_plugin_t plugin;
00088
00089 xmms_xform_methods_t methods;
00090
00091 GList *in_types;
00092 };
00093
00094 xmms_xform_t *xmms_xform_find (xmms_xform_t *prev, xmms_medialib_entry_t entry,
00095 GList *goal_hints);
00096 const char *xmms_xform_shortname (xmms_xform_t *xform);
00097 static xmms_xform_t *add_effects (xmms_xform_t *last,
00098 xmms_medialib_entry_t entry,
00099 GList *goal_formats);
00100 static xmms_xform_t *xmms_xform_new_effect (xmms_xform_t* last,
00101 xmms_medialib_entry_t entry,
00102 GList *goal_formats,
00103 const gchar *name);
00104 static void xmms_xform_destroy (xmms_object_t *object);
00105 static void effect_callbacks_init (void);
00106
00107 void
00108 xmms_xform_browse_add_entry_property_str (xmms_xform_t *xform,
00109 const gchar *key,
00110 const gchar *value)
00111 {
00112 xmmsv_t *val = xmmsv_new_string (value);
00113 xmms_xform_browse_add_entry_property (xform, key, val);
00114 xmmsv_unref (val);
00115 }
00116
00117
00118 void
00119 xmms_xform_browse_add_entry_property_int (xmms_xform_t *xform,
00120 const gchar *key,
00121 gint value)
00122 {
00123 xmmsv_t *val = xmmsv_new_int (value);
00124 xmms_xform_browse_add_entry_property (xform, key, val);
00125 xmmsv_unref (val);
00126 }
00127
00128 void
00129 xmms_xform_browse_add_symlink_args (xmms_xform_t *xform, const gchar *basename,
00130 const gchar *url, gint nargs, gchar **args)
00131 {
00132 GString *s;
00133 gchar *eurl;
00134 gchar bname[32];
00135 gint i;
00136
00137 if (!basename) {
00138 g_snprintf (bname, sizeof (bname), "%d", xform->browse_index++);
00139 basename = bname;
00140 }
00141
00142 xmms_xform_browse_add_entry (xform, basename, 0);
00143 eurl = xmms_medialib_url_encode (url);
00144 s = g_string_new (eurl);
00145
00146 for (i = 0; i < nargs; i++) {
00147 g_string_append_c (s, i == 0 ? '?' : '&');
00148 g_string_append (s, args[i]);
00149 }
00150
00151 xmms_xform_browse_add_entry_property_str (xform, "realpath", s->str);
00152
00153 g_free (eurl);
00154 g_string_free (s, TRUE);
00155 }
00156
00157 void
00158 xmms_xform_browse_add_symlink (xmms_xform_t *xform, const gchar *basename,
00159 const gchar *url)
00160 {
00161 xmms_xform_browse_add_symlink_args (xform, basename, url, 0, NULL);
00162 }
00163
00164 void
00165 xmms_xform_browse_add_entry_property (xmms_xform_t *xform, const gchar *key,
00166 xmmsv_t *val)
00167 {
00168 g_return_if_fail (xform);
00169 g_return_if_fail (xform->browse_dict);
00170 g_return_if_fail (key);
00171 g_return_if_fail (val);
00172
00173 xmmsv_dict_set (xform->browse_dict, key, val);
00174 }
00175
00176 void
00177 xmms_xform_browse_add_entry (xmms_xform_t *xform, const gchar *filename,
00178 guint32 flags)
00179 {
00180 xmmsv_t *val;
00181 const gchar *url;
00182 gchar *efile, *eurl, *t;
00183 gint l, isdir;
00184
00185 g_return_if_fail (filename);
00186
00187 t = strchr (filename, '/');
00188 g_return_if_fail (!t);
00189
00190 url = xmms_xform_get_url (xform);
00191 g_return_if_fail (url);
00192
00193 xform->browse_dict = xmmsv_new_dict ();
00194
00195 eurl = xmms_medialib_url_encode (url);
00196 efile = xmms_medialib_url_encode (filename);
00197
00198
00199
00200 l = strlen (url);
00201 if (l && url[l - 1] == '/') {
00202 t = g_strdup_printf ("%s%s", eurl, efile);
00203 } else {
00204 t = g_strdup_printf ("%s/%s", eurl, efile);
00205 }
00206
00207 isdir = !!(flags & XMMS_XFORM_BROWSE_FLAG_DIR);
00208 xmms_xform_browse_add_entry_property_str (xform, "path", t);
00209 xmms_xform_browse_add_entry_property_int (xform, "isdir", isdir);
00210
00211 val = xform->browse_dict;
00212 xform->browse_list = g_list_prepend (xform->browse_list, val);
00213
00214 g_free (t);
00215 g_free (efile);
00216 g_free (eurl);
00217 }
00218
00219 static gint
00220 xmms_browse_list_sortfunc (gconstpointer a, gconstpointer b)
00221 {
00222 int r1, r2;
00223 xmmsv_t *val1, *val2, *tmp1, *tmp2;
00224 const gchar *s1, *s2;
00225
00226 val1 = (xmmsv_t *) a;
00227 val2 = (xmmsv_t *) b;
00228
00229 g_return_val_if_fail (xmmsv_get_type (val1) == XMMSV_TYPE_DICT, 0);
00230 g_return_val_if_fail (xmmsv_get_type (val2) == XMMSV_TYPE_DICT, 0);
00231
00232 r1 = xmmsv_dict_get (val1, "intsort", &tmp1);
00233 r2 = xmmsv_dict_get (val2, "intsort", &tmp2);
00234
00235 if (r1 && r2) {
00236 gint i1, i2;
00237
00238 if (!xmmsv_get_int (tmp1, &i1))
00239 return 0;
00240 if (!xmmsv_get_int (tmp2, &i2))
00241 return 0;
00242 return i1 > i2;
00243 }
00244
00245 if (!xmmsv_dict_get (val1, "path", &tmp1))
00246 return 0;
00247 if (!xmmsv_dict_get (val2, "path", &tmp2))
00248 return 0;
00249
00250 if (!xmmsv_get_string (tmp1, &s1))
00251 return 0;
00252 if (!xmmsv_get_string (tmp2, &s2))
00253 return 0;
00254
00255 return xmms_natcmp (s1, s2);
00256 }
00257
00258 GList *
00259 xmms_xform_browse_method (xmms_xform_t *xform, const gchar *url,
00260 xmms_error_t *error)
00261 {
00262 GList *list = NULL;
00263
00264 if (xform->plugin->methods.browse) {
00265 if (!xform->plugin->methods.browse (xform, url, error)) {
00266 return NULL;
00267 }
00268 list = xform->browse_list;
00269 xform->browse_list = NULL;
00270 list = g_list_sort (list, xmms_browse_list_sortfunc);
00271 } else {
00272 xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
00273 }
00274
00275 return list;
00276 }
00277
00278 GList *
00279 xmms_xform_browse (xmms_xform_object_t *obj, const gchar *url,
00280 xmms_error_t *error)
00281 {
00282 GList *list = NULL;
00283 gchar *durl;
00284 xmms_xform_t *xform = NULL;
00285 xmms_xform_t *xform2 = NULL;
00286
00287 xform = xmms_xform_new (NULL, NULL, 0, NULL);
00288
00289 durl = g_strdup (url);
00290 xmms_medialib_decode_url (durl);
00291 XMMS_DBG ("url = %s", durl);
00292
00293 xmms_xform_outdata_type_add (xform,
00294 XMMS_STREAM_TYPE_MIMETYPE,
00295 "application/x-url",
00296 XMMS_STREAM_TYPE_URL,
00297 durl,
00298 XMMS_STREAM_TYPE_END);
00299
00300 xform2 = xmms_xform_find (xform, 0, NULL);
00301 if (xform2) {
00302 XMMS_DBG ("found xform %s", xmms_xform_shortname (xform2));
00303 } else {
00304 xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
00305 xmms_object_unref (xform);
00306 g_free (durl);
00307 return NULL;
00308 }
00309
00310 list = xmms_xform_browse_method (xform2, durl, error);
00311
00312 xmms_object_unref (xform);
00313 xmms_object_unref (xform2);
00314
00315 g_free (durl);
00316
00317 return list;
00318 }
00319
00320 XMMS_CMD_DEFINE (browse, xmms_xform_browse, xmms_xform_object_t *,
00321 LIST, STRING, NONE);
00322
00323 static void
00324 xmms_xform_object_destroy (xmms_object_t *obj)
00325 {
00326 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_XFORM);
00327 }
00328
00329 xmms_xform_object_t *
00330 xmms_xform_object_init (void)
00331 {
00332 xmms_xform_object_t *obj;
00333
00334 obj = xmms_object_new (xmms_xform_object_t, xmms_xform_object_destroy);
00335
00336 xmms_ipc_object_register (XMMS_IPC_OBJECT_XFORM, XMMS_OBJECT (obj));
00337
00338 xmms_object_cmd_add (XMMS_OBJECT (obj), XMMS_IPC_CMD_BROWSE,
00339 XMMS_CMD_FUNC (browse));
00340
00341 effect_callbacks_init ();
00342
00343 return obj;
00344 }
00345
00346 static void
00347 xmms_xform_destroy (xmms_object_t *object)
00348 {
00349 xmms_xform_t *xform = (xmms_xform_t *)object;
00350
00351 XMMS_DBG ("Freeing xform '%s'", xmms_xform_shortname (xform));
00352
00353
00354 if (xform->plugin && xform->plugin->methods.destroy && xform->inited) {
00355 xform->plugin->methods.destroy (xform);
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 (!plugin->methods.init (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 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 = xform->plugin->methods.read (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 = xform->plugin->methods.read (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 (!xform->plugin->methods.seek) {
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 = xform->plugin->methods.seek (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 static void
01143 xmms_xform_plugin_destroy (xmms_object_t *obj)
01144 {
01145 xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *)obj;
01146
01147 while (plugin->in_types) {
01148 xmms_object_unref (plugin->in_types->data);
01149
01150 plugin->in_types = g_list_delete_link (plugin->in_types,
01151 plugin->in_types);
01152 }
01153
01154 xmms_plugin_destroy ((xmms_plugin_t *)obj);
01155 }
01156
01157 xmms_plugin_t *
01158 xmms_xform_plugin_new (void)
01159 {
01160 xmms_xform_plugin_t *res;
01161
01162 res = xmms_object_new (xmms_xform_plugin_t, xmms_xform_plugin_destroy);
01163
01164 return (xmms_plugin_t *)res;
01165 }
01166
01167 void
01168 xmms_xform_plugin_methods_set (xmms_xform_plugin_t *plugin,
01169 xmms_xform_methods_t *methods)
01170 {
01171
01172 g_return_if_fail (plugin);
01173 g_return_if_fail (plugin->plugin.type == XMMS_PLUGIN_TYPE_XFORM);
01174
01175 XMMS_DBG ("Registering xform '%s'",
01176 xmms_plugin_shortname_get ((xmms_plugin_t *) plugin));
01177
01178 memcpy (&plugin->methods, methods, sizeof (xmms_xform_methods_t));
01179 }
01180
01181 gboolean
01182 xmms_xform_plugin_verify (xmms_plugin_t *_plugin)
01183 {
01184 xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *) _plugin;
01185
01186 g_return_val_if_fail (plugin, FALSE);
01187 g_return_val_if_fail (plugin->plugin.type == XMMS_PLUGIN_TYPE_XFORM, FALSE);
01188
01189
01190
01191 return TRUE;
01192 }
01193
01194 void
01195 xmms_xform_plugin_indata_add (xmms_xform_plugin_t *plugin, ...)
01196 {
01197 xmms_stream_type_t *t;
01198 va_list ap;
01199 gchar *config_key, config_value[32];
01200 gint priority;
01201
01202 va_start (ap, plugin);
01203 t = xmms_stream_type_parse (ap);
01204 va_end (ap);
01205
01206 config_key = g_strconcat ("priority.",
01207 xmms_stream_type_get_str (t, XMMS_STREAM_TYPE_NAME),
01208 NULL);
01209 priority = xmms_stream_type_get_int (t, XMMS_STREAM_TYPE_PRIORITY);
01210 g_snprintf (config_value, sizeof (config_value), "%d", priority);
01211 xmms_xform_plugin_config_property_register (plugin, config_key,
01212 config_value, NULL, NULL);
01213 g_free (config_key);
01214
01215 plugin->in_types = g_list_prepend (plugin->in_types, t);
01216 }
01217
01218 static gboolean
01219 xmms_xform_plugin_supports (xmms_xform_plugin_t *plugin, xmms_stream_type_t *st,
01220 gint *priority)
01221 {
01222 GList *t;
01223
01224 for (t = plugin->in_types; t; t = g_list_next (t)) {
01225 if (xmms_stream_type_match (t->data, st)) {
01226 if (priority) {
01227 gchar *config_key;
01228 xmms_config_property_t *conf_priority;
01229
01230 config_key = g_strconcat ("priority.",
01231 xmms_stream_type_get_str (t->data, XMMS_STREAM_TYPE_NAME),
01232 NULL);
01233 conf_priority = xmms_plugin_config_lookup ((xmms_plugin_t *)plugin,
01234 config_key);
01235 g_free (config_key);
01236
01237 if (conf_priority) {
01238 *priority = xmms_config_property_get_int (conf_priority);
01239 } else {
01240 *priority = XMMS_STREAM_TYPE_PRIORITY_DEFAULT;
01241 }
01242 }
01243 return TRUE;
01244 }
01245 }
01246 return FALSE;
01247 }
01248
01249 typedef struct match_state_St {
01250 xmms_xform_plugin_t *match;
01251 xmms_stream_type_t *out_type;
01252 gint priority;
01253 } match_state_t;
01254
01255 static gboolean
01256 xmms_xform_match (xmms_plugin_t *_plugin, gpointer user_data)
01257 {
01258 xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *)_plugin;
01259 match_state_t *state = (match_state_t *)user_data;
01260 gint priority;
01261
01262 g_assert (_plugin->type == XMMS_PLUGIN_TYPE_XFORM);
01263
01264 if (!plugin->in_types) {
01265 XMMS_DBG ("Skipping plugin '%s'", xmms_plugin_shortname_get (_plugin));
01266 return TRUE;
01267 }
01268
01269 XMMS_DBG ("Trying plugin '%s'", xmms_plugin_shortname_get (_plugin));
01270 if (xmms_xform_plugin_supports (plugin, state->out_type, &priority)) {
01271 XMMS_DBG ("Plugin '%s' matched (priority %d)",
01272 xmms_plugin_shortname_get (_plugin), priority);
01273 if (priority > state->priority) {
01274 if (state->match) {
01275 XMMS_DBG ("Using plugin '%s' (priority %d) instead of '%s' (priority %d)",
01276 xmms_plugin_shortname_get (_plugin), priority,
01277 xmms_plugin_shortname_get ((xmms_plugin_t *)state->match),
01278 state->priority);
01279 }
01280
01281 state->match = plugin;
01282 state->priority = priority;
01283 }
01284 }
01285
01286 return TRUE;
01287 }
01288
01289 xmms_xform_t *
01290 xmms_xform_find (xmms_xform_t *prev, xmms_medialib_entry_t entry,
01291 GList *goal_hints)
01292 {
01293 match_state_t state;
01294 xmms_xform_t *xform = NULL;
01295
01296 state.out_type = prev->out_type;
01297 state.match = NULL;
01298 state.priority = -1;
01299
01300 xmms_plugin_foreach (XMMS_PLUGIN_TYPE_XFORM, xmms_xform_match, &state);
01301
01302 if (state.match) {
01303 xform = xmms_xform_new (state.match, prev, entry, goal_hints);
01304 } else {
01305 XMMS_DBG ("Found no matching plugin...");
01306 }
01307
01308 return xform;
01309 }
01310
01311 gboolean
01312 xmms_xform_iseos (xmms_xform_t *xform)
01313 {
01314 gboolean ret = TRUE;
01315
01316 if (xform->prev) {
01317 ret = xform->prev->eos;
01318 }
01319
01320 return ret;
01321 }
01322
01323 const xmms_stream_type_t *
01324 xmms_xform_get_out_stream_type (xmms_xform_t *xform)
01325 {
01326 return xform->out_type;
01327 }
01328
01329 const GList *
01330 xmms_xform_goal_hints_get (xmms_xform_t *xform)
01331 {
01332 return xform->goal_hints;
01333 }
01334
01335
01336 static gboolean
01337 has_goalformat (xmms_xform_t *xform, GList *goal_formats)
01338 {
01339 const xmms_stream_type_t *current;
01340 gboolean ret = FALSE;
01341 GList *n;
01342
01343 current = xmms_xform_get_out_stream_type (xform);
01344
01345 for (n = goal_formats; n; n = g_list_next (n)) {
01346 xmms_stream_type_t *goal_type = n->data;
01347 if (xmms_stream_type_match (goal_type, current)) {
01348 ret = TRUE;
01349 break;
01350 }
01351
01352 }
01353
01354 if (!ret) {
01355 XMMS_DBG ("Not in one of %d goal-types", g_list_length (goal_formats));
01356 }
01357
01358 return ret;
01359 }
01360
01361 static void
01362 outdata_type_metadata_collect (xmms_xform_t *xform)
01363 {
01364 gint val;
01365 const char *mime;
01366 xmms_stream_type_t *type;
01367
01368 type = xform->out_type;
01369 mime = xmms_stream_type_get_str (type, XMMS_STREAM_TYPE_MIMETYPE);
01370 if (strcmp (mime, "audio/pcm") != 0) {
01371 return;
01372 }
01373
01374 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_FORMAT);
01375 if (val != -1) {
01376 const gchar *name = xmms_sample_name_get ((xmms_sample_format_t) val);
01377 xmms_xform_metadata_set_str (xform,
01378 XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLE_FMT,
01379 name);
01380 }
01381
01382 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
01383 if (val != -1) {
01384 xmms_xform_metadata_set_int (xform,
01385 XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE,
01386 val);
01387 }
01388
01389 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_CHANNELS);
01390 if (val != -1) {
01391 xmms_xform_metadata_set_int (xform,
01392 XMMS_MEDIALIB_ENTRY_PROPERTY_CHANNELS,
01393 val);
01394 }
01395 }
01396
01397 static xmms_xform_t *
01398 chain_setup (xmms_medialib_entry_t entry, const gchar *url, GList *goal_formats)
01399 {
01400 xmms_xform_t *xform, *last;
01401 gchar *durl, *args;
01402
01403 if (!entry) {
01404 entry = 1;
01405 }
01406
01407 xform = xmms_xform_new (NULL, NULL, 0, goal_formats);
01408
01409 durl = g_strdup (url);
01410
01411 args = strchr (durl, '?');
01412 if (args) {
01413 gchar **params;
01414 gint i;
01415 *args = 0;
01416 args++;
01417 xmms_medialib_decode_url (args);
01418
01419 params = g_strsplit (args, "&", 0);
01420
01421 for (i = 0; params && params[i]; i++) {
01422 gchar *v;
01423 v = strchr (params[i], '=');
01424 if (v) {
01425 *v = 0;
01426 v++;
01427 xmms_xform_metadata_set_str (xform, params[i], v);
01428 } else {
01429 xmms_xform_metadata_set_int (xform, params[i], 1);
01430 }
01431 }
01432 g_strfreev (params);
01433 }
01434 xmms_medialib_decode_url (durl);
01435
01436 xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE,
01437 "application/x-url", XMMS_STREAM_TYPE_URL,
01438 durl, XMMS_STREAM_TYPE_END);
01439
01440 g_free (durl);
01441
01442 last = xform;
01443
01444 do {
01445 xform = xmms_xform_find (last, entry, goal_formats);
01446 if (!xform) {
01447 xmms_log_error ("Couldn't set up chain for '%s' (%d)",
01448 url, entry);
01449 xmms_object_unref (last);
01450
01451 return NULL;
01452 }
01453 xmms_object_unref (last);
01454 last = xform;
01455 } while (!has_goalformat (xform, goal_formats));
01456
01457 outdata_type_metadata_collect (last);
01458
01459 return last;
01460 }
01461
01462 void
01463 chain_finalize (xmms_xform_t *xform, xmms_medialib_entry_t entry,
01464 const gchar *url, gboolean rehashing)
01465 {
01466 GString *namestr;
01467
01468 namestr = g_string_new ("");
01469 xmms_xform_metadata_collect (xform, namestr, rehashing);
01470 xmms_log_info ("Successfully setup chain for '%s' (%d) containing %s",
01471 url, entry, namestr->str);
01472
01473 g_string_free (namestr, TRUE);
01474 }
01475
01476 gchar *
01477 get_url_for_entry (xmms_medialib_entry_t entry)
01478 {
01479 xmms_medialib_session_t *session;
01480 gchar *url = NULL;
01481
01482 session = xmms_medialib_begin ();
01483 url = xmms_medialib_entry_property_get_str (session, entry,
01484 XMMS_MEDIALIB_ENTRY_PROPERTY_URL);
01485 xmms_medialib_end (session);
01486
01487 if (!url) {
01488 xmms_log_error ("Couldn't get url for entry (%d)", entry);
01489 }
01490
01491 return url;
01492 }
01493
01494 xmms_xform_t *
01495 xmms_xform_chain_setup (xmms_medialib_entry_t entry, GList *goal_formats,
01496 gboolean rehash)
01497 {
01498 gchar *url;
01499 xmms_xform_t *xform;
01500
01501 if (!(url = get_url_for_entry (entry))) {
01502 return NULL;
01503 }
01504
01505 xform = xmms_xform_chain_setup_url (entry, url, goal_formats, rehash);
01506 g_free (url);
01507
01508 return xform;
01509 }
01510
01511 xmms_xform_t *
01512 xmms_xform_chain_setup_url (xmms_medialib_entry_t entry, const gchar *url,
01513 GList *goal_formats, gboolean rehash)
01514 {
01515 xmms_xform_t *last;
01516 xmms_plugin_t *plugin;
01517 xmms_xform_plugin_t *xform_plugin;
01518 gboolean add_segment = FALSE;
01519
01520 last = chain_setup (entry, url, goal_formats);
01521 if (!last) {
01522 return NULL;
01523 }
01524
01525
01526 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, "segment");
01527 xform_plugin = (xmms_xform_plugin_t *) plugin;
01528
01529
01530
01531 if (xform_plugin) {
01532 add_segment = xmms_xform_plugin_supports (xform_plugin,
01533 last->out_type,
01534 NULL);
01535 xmms_object_unref (plugin);
01536 }
01537
01538
01539 if (add_segment) {
01540 last = xmms_xform_new_effect (last, entry, goal_formats, "segment");
01541 if (!last) {
01542 return NULL;
01543 }
01544 }
01545
01546
01547 if (!rehash) {
01548 last = add_effects (last, entry, goal_formats);
01549 if (!last) {
01550 return NULL;
01551 }
01552 }
01553
01554 chain_finalize (last, entry, url, rehash);
01555 return last;
01556 }
01557
01558 xmms_config_property_t *
01559 xmms_xform_plugin_config_property_register (xmms_xform_plugin_t *xform_plugin,
01560 const gchar *name,
01561 const gchar *default_value,
01562 xmms_object_handler_t cb,
01563 gpointer userdata)
01564 {
01565 xmms_plugin_t *plugin = (xmms_plugin_t *) xform_plugin;
01566
01567 return xmms_plugin_config_property_register (plugin, name,
01568 default_value,
01569 cb, userdata);
01570 }
01571
01572 xmms_config_property_t *
01573 xmms_xform_config_lookup (xmms_xform_t *xform, const gchar *path)
01574 {
01575 g_return_val_if_fail (xform->plugin, NULL);
01576
01577 return xmms_plugin_config_lookup ((xmms_plugin_t *) xform->plugin, path);
01578 }
01579
01580 static xmms_xform_t *
01581 add_effects (xmms_xform_t *last, xmms_medialib_entry_t entry,
01582 GList *goal_formats)
01583 {
01584 gint effect_no;
01585
01586 for (effect_no = 0; TRUE; effect_no++) {
01587 xmms_config_property_t *cfg;
01588 gchar key[64];
01589 const gchar *name;
01590
01591 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
01592
01593 cfg = xmms_config_lookup (key);
01594 if (!cfg) {
01595 break;
01596 }
01597
01598 name = xmms_config_property_get_string (cfg);
01599
01600 if (!name[0]) {
01601 continue;
01602 }
01603
01604 last = xmms_xform_new_effect (last, entry, goal_formats, name);
01605 }
01606
01607 return last;
01608 }
01609
01610 static xmms_xform_t *
01611 xmms_xform_new_effect (xmms_xform_t *last, xmms_medialib_entry_t entry,
01612 GList *goal_formats, const gchar *name)
01613 {
01614 xmms_plugin_t *plugin;
01615 xmms_xform_plugin_t *xform_plugin;
01616 xmms_xform_t *xform;
01617
01618 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01619 if (!plugin) {
01620 xmms_log_error ("Couldn't find any effect named '%s'", name);
01621 return last;
01622 }
01623
01624 xform_plugin = (xmms_xform_plugin_t *) plugin;
01625 if (!xmms_xform_plugin_supports (xform_plugin, last->out_type, NULL)) {
01626 xmms_log_info ("Effect '%s' doesn't support format, skipping",
01627 xmms_plugin_shortname_get (plugin));
01628 xmms_object_unref (plugin);
01629 return last;
01630 }
01631
01632 xform = xmms_xform_new (xform_plugin, last, entry, goal_formats);
01633
01634 if (xform) {
01635 xmms_object_unref (last);
01636 last = xform;
01637 } else {
01638 xmms_log_info ("Effect '%s' failed to initialize, skipping",
01639 xmms_plugin_shortname_get (plugin));
01640 }
01641 xmms_xform_plugin_config_property_register (xform_plugin,
01642 "enabled", "0",
01643 NULL, NULL);
01644 xmms_object_unref (plugin);
01645 return last;
01646 }
01647
01648 static void
01649 update_effect_properties (xmms_object_t *object, xmmsv_t *data,
01650 gpointer userdata)
01651 {
01652 gint effect_no = GPOINTER_TO_INT (userdata);
01653 const gchar *name;
01654
01655 xmms_config_property_t *cfg;
01656 xmms_xform_plugin_t *xform_plugin;
01657 xmms_plugin_t *plugin;
01658 gchar key[64];
01659
01660 name = xmms_config_property_get_string ((xmms_config_property_t *) object);
01661
01662 if (name[0]) {
01663 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01664 if (!plugin) {
01665 xmms_log_error ("Couldn't find any effect named '%s'", name);
01666 } else {
01667 xform_plugin = (xmms_xform_plugin_t *) plugin;
01668 xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
01669 "1", NULL, NULL);
01670 xmms_object_unref (plugin);
01671 }
01672
01673
01674 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no + 1);
01675
01676 cfg = xmms_config_lookup (key);
01677 if (!cfg) {
01678 xmms_config_property_register (key, "", update_effect_properties,
01679 GINT_TO_POINTER (effect_no + 1));
01680 }
01681 }
01682 }
01683
01684 static void
01685 effect_callbacks_init (void)
01686 {
01687 gint effect_no;
01688
01689 xmms_config_property_t *cfg;
01690 xmms_xform_plugin_t *xform_plugin;
01691 xmms_plugin_t *plugin;
01692 gchar key[64];
01693 const gchar *name;
01694
01695 for (effect_no = 0; ; effect_no++) {
01696 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
01697
01698 cfg = xmms_config_lookup (key);
01699 if (!cfg) {
01700 break;
01701 }
01702 xmms_config_property_callback_set (cfg, update_effect_properties,
01703 GINT_TO_POINTER (effect_no));
01704
01705 name = xmms_config_property_get_string (cfg);
01706 if (!name[0]) {
01707 continue;
01708 }
01709
01710 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01711 if (!plugin) {
01712 xmms_log_error ("Couldn't find any effect named '%s'", name);
01713 continue;
01714 }
01715
01716 xform_plugin = (xmms_xform_plugin_t *) plugin;
01717 xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
01718 "1", NULL, NULL);
01719
01720 xmms_object_unref (plugin);
01721 }
01722
01723
01724
01725 if ((!effect_no) || name[0]) {
01726 xmms_config_property_register (key, "", update_effect_properties,
01727 GINT_TO_POINTER (effect_no));
01728 }
01729 }
01730