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 (const gchar *url, xmms_error_t *error)
00280 {
00281 GList *list = NULL;
00282 gchar *durl;
00283 xmms_xform_t *xform = NULL;
00284 xmms_xform_t *xform2 = NULL;
00285
00286 xform = xmms_xform_new (NULL, NULL, 0, NULL);
00287
00288 durl = g_strdup (url);
00289 xmms_medialib_decode_url (durl);
00290 XMMS_DBG ("url = %s", durl);
00291
00292 xmms_xform_outdata_type_add (xform,
00293 XMMS_STREAM_TYPE_MIMETYPE,
00294 "application/x-url",
00295 XMMS_STREAM_TYPE_URL,
00296 durl,
00297 XMMS_STREAM_TYPE_END);
00298
00299 xform2 = xmms_xform_find (xform, 0, NULL);
00300 if (xform2) {
00301 XMMS_DBG ("found xform %s", xmms_xform_shortname (xform2));
00302 } else {
00303 xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
00304 xmms_object_unref (xform);
00305 g_free (durl);
00306 return NULL;
00307 }
00308
00309 list = xmms_xform_browse_method (xform2, durl, error);
00310
00311 xmms_object_unref (xform);
00312 xmms_object_unref (xform2);
00313
00314 g_free (durl);
00315
00316 return list;
00317 }
00318
00319 static GList *
00320 xmms_xform_client_browse (xmms_xform_object_t *obj, const gchar *url,
00321 xmms_error_t *error)
00322 {
00323 return xmms_xform_browse (url, error);
00324 }
00325 XMMS_CMD_DEFINE (browse, xmms_xform_client_browse, xmms_xform_object_t *,
00326 LIST, STRING, NONE);
00327
00328 static void
00329 xmms_xform_object_destroy (xmms_object_t *obj)
00330 {
00331 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_XFORM);
00332 }
00333
00334 xmms_xform_object_t *
00335 xmms_xform_object_init (void)
00336 {
00337 xmms_xform_object_t *obj;
00338
00339 obj = xmms_object_new (xmms_xform_object_t, xmms_xform_object_destroy);
00340
00341 xmms_ipc_object_register (XMMS_IPC_OBJECT_XFORM, XMMS_OBJECT (obj));
00342
00343 xmms_object_cmd_add (XMMS_OBJECT (obj), XMMS_IPC_CMD_BROWSE,
00344 XMMS_CMD_FUNC (browse));
00345
00346 effect_callbacks_init ();
00347
00348 return obj;
00349 }
00350
00351 static void
00352 xmms_xform_destroy (xmms_object_t *object)
00353 {
00354 xmms_xform_t *xform = (xmms_xform_t *)object;
00355
00356 XMMS_DBG ("Freeing xform '%s'", xmms_xform_shortname (xform));
00357
00358
00359 if (xform->plugin && xform->plugin->methods.destroy && xform->inited) {
00360 xform->plugin->methods.destroy (xform);
00361 }
00362
00363 g_hash_table_destroy (xform->metadata);
00364
00365 g_hash_table_destroy (xform->privdata);
00366 g_queue_free (xform->hotspots);
00367
00368 g_free (xform->buffer);
00369
00370 xmms_object_unref (xform->out_type);
00371 xmms_object_unref (xform->plugin);
00372
00373 if (xform->prev) {
00374 xmms_object_unref (xform->prev);
00375 }
00376
00377 }
00378
00379 xmms_xform_t *
00380 xmms_xform_new (xmms_xform_plugin_t *plugin, xmms_xform_t *prev,
00381 xmms_medialib_entry_t entry, GList *goal_hints)
00382 {
00383 xmms_xform_t *xform;
00384
00385 xform = xmms_object_new (xmms_xform_t, xmms_xform_destroy);
00386
00387 xmms_object_ref (plugin);
00388 xform->plugin = plugin;
00389 xform->entry = entry;
00390 xform->goal_hints = goal_hints;
00391 xform->lr.bufend = &xform->lr.buf[0];
00392
00393 if (prev) {
00394 xmms_object_ref (prev);
00395 xform->prev = prev;
00396 }
00397
00398 xform->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
00399 g_free,
00400 (GDestroyNotify) xmmsv_unref);
00401
00402 xform->privdata = g_hash_table_new_full (g_str_hash, g_str_equal,
00403 g_free,
00404 (GDestroyNotify) xmmsv_unref);
00405 xform->hotspots = g_queue_new ();
00406
00407 if (plugin && entry) {
00408 if (!plugin->methods.init (xform)) {
00409 xmms_object_unref (xform);
00410 return NULL;
00411 }
00412 xform->inited = TRUE;
00413 g_return_val_if_fail (xform->out_type, NULL);
00414 }
00415
00416 xform->buffer = g_malloc (READ_CHUNK);
00417 xform->buffersize = READ_CHUNK;
00418
00419 return xform;
00420 }
00421
00422 xmms_medialib_entry_t
00423 xmms_xform_entry_get (xmms_xform_t *xform)
00424 {
00425 return xform->entry;
00426 }
00427
00428 gpointer
00429 xmms_xform_private_data_get (xmms_xform_t *xform)
00430 {
00431 return xform->priv;
00432 }
00433
00434 void
00435 xmms_xform_private_data_set (xmms_xform_t *xform, gpointer data)
00436 {
00437 xform->priv = data;
00438 }
00439
00440 void
00441 xmms_xform_outdata_type_add (xmms_xform_t *xform, ...)
00442 {
00443 va_list ap;
00444 va_start (ap, xform);
00445 xform->out_type = xmms_stream_type_parse (ap);
00446 va_end (ap);
00447 }
00448
00449 void
00450 xmms_xform_outdata_type_set (xmms_xform_t *xform, xmms_stream_type_t *type)
00451 {
00452 xmms_object_ref (type);
00453 xform->out_type = type;
00454 }
00455
00456 void
00457 xmms_xform_outdata_type_copy (xmms_xform_t *xform)
00458 {
00459 xmms_object_ref (xform->prev->out_type);
00460 xform->out_type = xform->prev->out_type;
00461 }
00462
00463 const char *
00464 xmms_xform_indata_find_str (xmms_xform_t *xform, xmms_stream_type_key_t key)
00465 {
00466 const gchar *r;
00467 r = xmms_stream_type_get_str (xform->prev->out_type, key);
00468 if (r) {
00469 return r;
00470 } else if (xform->prev) {
00471 return xmms_xform_indata_find_str (xform->prev, key);
00472 }
00473 return NULL;
00474 }
00475
00476 const char *
00477 xmms_xform_indata_get_str (xmms_xform_t *xform, xmms_stream_type_key_t key)
00478 {
00479 return xmms_stream_type_get_str (xform->prev->out_type, key);
00480 }
00481
00482 gint
00483 xmms_xform_indata_get_int (xmms_xform_t *xform, xmms_stream_type_key_t key)
00484 {
00485 return xmms_stream_type_get_int (xform->prev->out_type, key);
00486 }
00487
00488 xmms_stream_type_t *
00489 xmms_xform_outtype_get (xmms_xform_t *xform)
00490 {
00491 return xform->out_type;
00492 }
00493
00494 xmms_stream_type_t *
00495 xmms_xform_intype_get (xmms_xform_t *xform)
00496 {
00497 return xmms_xform_outtype_get (xform->prev);
00498 }
00499
00500
00501
00502 const char *
00503 xmms_xform_outtype_get_str (xmms_xform_t *xform, xmms_stream_type_key_t key)
00504 {
00505 return xmms_stream_type_get_str (xform->out_type, key);
00506 }
00507
00508 gint
00509 xmms_xform_outtype_get_int (xmms_xform_t *xform, xmms_stream_type_key_t key)
00510 {
00511 return xmms_stream_type_get_int (xform->out_type, key);
00512 }
00513
00514
00515 void
00516 xmms_xform_metadata_set_int (xmms_xform_t *xform, const char *key, int val)
00517 {
00518 XMMS_DBG ("Setting '%s' to %d", key, val);
00519 g_hash_table_insert (xform->metadata, g_strdup (key),
00520 xmmsv_new_int (val));
00521 xform->metadata_changed = TRUE;
00522 }
00523
00524 void
00525 xmms_xform_metadata_set_str (xmms_xform_t *xform, const char *key,
00526 const char *val)
00527 {
00528 const char *old;
00529
00530 if (!g_utf8_validate (val, -1, NULL)) {
00531 xmms_log_error ("xform '%s' tried to set property '%s' to a NON UTF-8 string!", xmms_xform_shortname (xform), key);
00532 return;
00533 }
00534
00535 if (xmms_xform_metadata_get_str (xform, key, &old)) {
00536 if (strcmp (old, val) == 0) {
00537 return;
00538 }
00539 }
00540
00541 g_hash_table_insert (xform->metadata, g_strdup (key),
00542 xmmsv_new_string (val));
00543
00544 xform->metadata_changed = TRUE;
00545 }
00546
00547 static const xmmsv_t *
00548 xmms_xform_metadata_get_val (xmms_xform_t *xform, const char *key)
00549 {
00550 xmmsv_t *val = NULL;
00551
00552 for (; xform; xform = xform->prev) {
00553 val = g_hash_table_lookup (xform->metadata, key);
00554 if (val) {
00555 break;
00556 }
00557 }
00558
00559 return val;
00560 }
00561
00562 gboolean
00563 xmms_xform_metadata_has_val (xmms_xform_t *xform, const gchar *key)
00564 {
00565 return !!xmms_xform_metadata_get_val (xform, key);
00566 }
00567
00568 gboolean
00569 xmms_xform_metadata_get_int (xmms_xform_t *xform, const char *key,
00570 gint32 *val)
00571 {
00572 const xmmsv_t *obj;
00573 gboolean ret = FALSE;
00574
00575 obj = xmms_xform_metadata_get_val (xform, key);
00576 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) {
00577 xmmsv_get_int (obj, val);
00578 ret = TRUE;
00579 }
00580
00581 return ret;
00582 }
00583
00584 gboolean
00585 xmms_xform_metadata_get_str (xmms_xform_t *xform, const char *key,
00586 const gchar **val)
00587 {
00588 const xmmsv_t *obj;
00589 gboolean ret = FALSE;
00590
00591 obj = xmms_xform_metadata_get_val (xform, key);
00592 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) {
00593 xmmsv_get_string (obj, val);
00594 ret = TRUE;
00595 }
00596
00597 return ret;
00598 }
00599
00600 typedef struct {
00601 xmms_medialib_session_t *session;
00602 xmms_medialib_entry_t entry;
00603 guint32 source;
00604 } metadata_festate_t;
00605
00606 static void
00607 add_metadatum (gpointer _key, gpointer _value, gpointer user_data)
00608 {
00609 xmmsv_t *value = (xmmsv_t *) _value;
00610 gchar *key = (gchar *) _key;
00611 metadata_festate_t *st = (metadata_festate_t *) user_data;
00612
00613 if (xmmsv_get_type (value) == XMMSV_TYPE_STRING) {
00614 const gchar *s;
00615 xmmsv_get_string (value, &s);
00616 xmms_medialib_entry_property_set_str_source (st->session,
00617 st->entry,
00618 key,
00619 s,
00620 st->source);
00621 } else if (xmmsv_get_type (value) == XMMSV_TYPE_INT32) {
00622 gint i;
00623 xmmsv_get_int (value, &i);
00624 xmms_medialib_entry_property_set_int_source (st->session,
00625 st->entry,
00626 key,
00627 i,
00628 st->source);
00629 } else {
00630 XMMS_DBG ("Unknown type?!?");
00631 }
00632 }
00633
00634 static void
00635 xmms_xform_metadata_collect_one (xmms_xform_t *xform, metadata_festate_t *info)
00636 {
00637 gchar src[XMMS_PLUGIN_SHORTNAME_MAX_LEN + 8];
00638
00639 XMMS_DBG ("Collecting metadata from %s", xmms_xform_shortname (xform));
00640
00641 g_snprintf (src, sizeof (src), "plugin/%s",
00642 xmms_xform_shortname (xform));
00643
00644 info->source = xmms_medialib_source_to_id (info->session, src);
00645 g_hash_table_foreach (xform->metadata, add_metadatum, info);
00646
00647 xform->metadata_changed = FALSE;
00648 }
00649
00650 static void
00651 xmms_xform_metadata_collect_r (xmms_xform_t *xform, metadata_festate_t *info,
00652 GString *namestr)
00653 {
00654 if (xform->prev) {
00655 xmms_xform_metadata_collect_r (xform->prev, info, namestr);
00656 }
00657
00658 if (xform->plugin) {
00659 if (namestr->len) {
00660 g_string_append_c (namestr, ':');
00661 }
00662 g_string_append (namestr, xmms_xform_shortname (xform));
00663 }
00664
00665 if (xform->metadata_changed) {
00666 xmms_xform_metadata_collect_one (xform, info);
00667 }
00668
00669 xform->metadata_collected = TRUE;
00670 }
00671
00672 static void
00673 xmms_xform_metadata_collect (xmms_xform_t *start, GString *namestr, gboolean rehashing)
00674 {
00675 metadata_festate_t info;
00676 gint times_played;
00677 gint last_started;
00678 GTimeVal now;
00679
00680 info.entry = start->entry;
00681 info.session = xmms_medialib_begin_write ();
00682
00683 times_played = xmms_medialib_entry_property_get_int (info.session,
00684 info.entry,
00685 XMMS_MEDIALIB_ENTRY_PROPERTY_TIMESPLAYED);
00686
00687
00688
00689
00690 if (times_played < 0) {
00691 times_played = 0;
00692 }
00693
00694 last_started = xmms_medialib_entry_property_get_int (info.session,
00695 info.entry,
00696 XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED);
00697
00698 xmms_medialib_entry_cleanup (info.session, info.entry);
00699
00700 xmms_xform_metadata_collect_r (start, &info, namestr);
00701
00702 xmms_medialib_entry_property_set_str (info.session, info.entry,
00703 XMMS_MEDIALIB_ENTRY_PROPERTY_CHAIN,
00704 namestr->str);
00705
00706 xmms_medialib_entry_property_set_int (info.session, info.entry,
00707 XMMS_MEDIALIB_ENTRY_PROPERTY_TIMESPLAYED,
00708 times_played + (rehashing ? 0 : 1));
00709
00710 if (!rehashing || (rehashing && last_started)) {
00711 g_get_current_time (&now);
00712
00713 xmms_medialib_entry_property_set_int (info.session, info.entry,
00714 XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED,
00715 (rehashing ? last_started : now.tv_sec));
00716 }
00717
00718 xmms_medialib_entry_status_set (info.session, info.entry,
00719 XMMS_MEDIALIB_ENTRY_STATUS_OK);
00720
00721 xmms_medialib_end (info.session);
00722 xmms_medialib_entry_send_update (info.entry);
00723 }
00724
00725 static void
00726 xmms_xform_metadata_update (xmms_xform_t *xform)
00727 {
00728 metadata_festate_t info;
00729
00730 info.entry = xform->entry;
00731 info.session = xmms_medialib_begin_write ();
00732
00733 xmms_xform_metadata_collect_one (xform, &info);
00734
00735 xmms_medialib_end (info.session);
00736 xmms_medialib_entry_send_update (info.entry);
00737 }
00738
00739 static void
00740 xmms_xform_auxdata_set_val (xmms_xform_t *xform, char *key, xmmsv_t *val)
00741 {
00742 xmms_xform_hotspot_t *hs;
00743
00744 hs = g_new0 (xmms_xform_hotspot_t, 1);
00745 hs->pos = xform->buffered;
00746 hs->key = key;
00747 hs->obj = val;
00748
00749 g_queue_push_tail (xform->hotspots, hs);
00750 }
00751
00752 void
00753 xmms_xform_auxdata_barrier (xmms_xform_t *xform)
00754 {
00755 xmmsv_t *val = xmmsv_new_none ();
00756 xmms_xform_auxdata_set_val (xform, NULL, val);
00757 }
00758
00759 void
00760 xmms_xform_auxdata_set_int (xmms_xform_t *xform, const char *key, int intval)
00761 {
00762 xmmsv_t *val = xmmsv_new_int (intval);
00763 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
00764 }
00765
00766 void
00767 xmms_xform_auxdata_set_str (xmms_xform_t *xform, const gchar *key,
00768 const gchar *strval)
00769 {
00770 xmmsv_t *val;
00771 const char *old;
00772
00773 if (xmms_xform_auxdata_get_str (xform, key, &old)) {
00774 if (strcmp (old, strval) == 0) {
00775 return;
00776 }
00777 }
00778
00779 val = xmmsv_new_string (strval);
00780 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
00781 }
00782
00783 void
00784 xmms_xform_auxdata_set_bin (xmms_xform_t *xform, const gchar *key,
00785 gpointer data, gssize len)
00786 {
00787 xmmsv_t *val;
00788
00789 val = xmmsv_new_bin (data, len);
00790 xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
00791 }
00792
00793 static const xmmsv_t *
00794 xmms_xform_auxdata_get_val (xmms_xform_t *xform, const gchar *key)
00795 {
00796 guint i;
00797 xmms_xform_hotspot_t *hs;
00798 xmmsv_t *val = NULL;
00799
00800
00801 xform = xform->prev;
00802
00803
00804 for (i=0; (hs = g_queue_peek_nth (xform->hotspots, i)) != NULL; i++) {
00805 if (hs->pos != 0) {
00806 break;
00807 } else if (hs->key && !strcmp (key, hs->key)) {
00808 val = hs->obj;
00809 }
00810 }
00811
00812 if (!val) {
00813 val = g_hash_table_lookup (xform->privdata, key);
00814 }
00815
00816 return val;
00817 }
00818
00819 gboolean
00820 xmms_xform_auxdata_has_val (xmms_xform_t *xform, const gchar *key)
00821 {
00822 return !!xmms_xform_auxdata_get_val (xform, key);
00823 }
00824
00825 gboolean
00826 xmms_xform_auxdata_get_int (xmms_xform_t *xform, const gchar *key, gint32 *val)
00827 {
00828 const xmmsv_t *obj;
00829
00830 obj = xmms_xform_auxdata_get_val (xform, key);
00831 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) {
00832 xmmsv_get_int (obj, val);
00833 return TRUE;
00834 }
00835
00836 return FALSE;
00837 }
00838
00839 gboolean
00840 xmms_xform_auxdata_get_str (xmms_xform_t *xform, const gchar *key,
00841 const gchar **val)
00842 {
00843 const xmmsv_t *obj;
00844
00845 obj = xmms_xform_auxdata_get_val (xform, key);
00846 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) {
00847 xmmsv_get_string (obj, val);
00848 return TRUE;
00849 }
00850
00851 return FALSE;
00852 }
00853
00854 gboolean
00855 xmms_xform_auxdata_get_bin (xmms_xform_t *xform, const gchar *key,
00856 const guchar **data, gsize *datalen)
00857 {
00858 const xmmsv_t *obj;
00859
00860 obj = xmms_xform_auxdata_get_val (xform, key);
00861 if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_BIN) {
00862 xmmsv_get_bin (obj, data, datalen);
00863 return TRUE;
00864 }
00865
00866 return FALSE;
00867 }
00868
00869 const char *
00870 xmms_xform_shortname (xmms_xform_t *xform)
00871 {
00872 return (xform->plugin)
00873 ? xmms_plugin_shortname_get ((xmms_plugin_t *) xform->plugin)
00874 : "unknown";
00875 }
00876
00877 static gint
00878 xmms_xform_this_peek (xmms_xform_t *xform, gpointer buf, gint siz,
00879 xmms_error_t *err)
00880 {
00881 while (xform->buffered < siz) {
00882 gint res;
00883
00884 if (xform->buffered + READ_CHUNK > xform->buffersize) {
00885 xform->buffersize *= 2;
00886 xform->buffer = g_realloc (xform->buffer, xform->buffersize);
00887 }
00888
00889 res = xform->plugin->methods.read (xform,
00890 &xform->buffer[xform->buffered],
00891 READ_CHUNK, err);
00892
00893 if (res < -1) {
00894 XMMS_DBG ("Read method of %s returned bad value (%d) - BUG IN PLUGIN",
00895 xmms_xform_shortname (xform), res);
00896 res = -1;
00897 }
00898
00899 if (res == 0) {
00900 xform->eos = TRUE;
00901 break;
00902 } else if (res == -1) {
00903 xform->error = TRUE;
00904 return -1;
00905 } else {
00906 xform->buffered += res;
00907 }
00908 }
00909
00910
00911 siz = MIN (siz, xform->buffered);
00912 memcpy (buf, xform->buffer, siz);
00913 return siz;
00914 }
00915
00916 static void
00917 xmms_xform_hotspot_callback (gpointer data, gpointer user_data)
00918 {
00919 xmms_xform_hotspot_t *hs = data;
00920 gint *read = user_data;
00921
00922 hs->pos -= *read;
00923 }
00924
00925 static gint
00926 xmms_xform_hotspots_update (xmms_xform_t *xform)
00927 {
00928 xmms_xform_hotspot_t *hs;
00929 gint ret = -1;
00930
00931 hs = g_queue_peek_head (xform->hotspots);
00932 while (hs != NULL && hs->pos == 0) {
00933 g_queue_pop_head (xform->hotspots);
00934 if (hs->key) {
00935 g_hash_table_insert (xform->privdata, hs->key, hs->obj);
00936 }
00937 hs = g_queue_peek_head (xform->hotspots);
00938 }
00939
00940 if (hs != NULL) {
00941 ret = hs->pos;
00942 }
00943
00944 return ret;
00945 }
00946
00947 gint
00948 xmms_xform_this_read (xmms_xform_t *xform, gpointer buf, gint siz,
00949 xmms_error_t *err)
00950 {
00951 gint read = 0;
00952 gint nexths;
00953
00954 if (xform->error) {
00955 xmms_error_set (err, XMMS_ERROR_GENERIC, "Read on errored xform");
00956 return -1;
00957 }
00958
00959
00960 nexths = xmms_xform_hotspots_update (xform);
00961 if (nexths >= 0) {
00962 siz = MIN (siz, nexths);
00963 }
00964
00965 if (xform->buffered) {
00966 read = MIN (siz, xform->buffered);
00967 memcpy (buf, xform->buffer, read);
00968 xform->buffered -= read;
00969
00970
00971 g_queue_foreach (xform->hotspots, &xmms_xform_hotspot_callback, &read);
00972
00973 if (xform->buffered) {
00974
00975
00976 memmove (xform->buffer, &xform->buffer[read], xform->buffered);
00977 }
00978 }
00979
00980 if (xform->eos) {
00981 return read;
00982 }
00983
00984 while (read < siz) {
00985 gint res;
00986
00987 res = xform->plugin->methods.read (xform, buf + read, siz - read, err);
00988 if (xform->metadata_collected && xform->metadata_changed)
00989 xmms_xform_metadata_update (xform);
00990
00991 if (res < -1) {
00992 XMMS_DBG ("Read method of %s returned bad value (%d) - BUG IN PLUGIN", xmms_xform_shortname (xform), res);
00993 res = -1;
00994 }
00995
00996 if (res == 0) {
00997 xform->eos = TRUE;
00998 break;
00999 } else if (res == -1) {
01000 xform->error = TRUE;
01001 return -1;
01002 } else {
01003 if (read == 0)
01004 xmms_xform_hotspots_update (xform);
01005
01006 if (!g_queue_is_empty (xform->hotspots)) {
01007 if (xform->buffered + res > xform->buffersize) {
01008 xform->buffersize = MAX (xform->buffersize * 2,
01009 xform->buffersize + res);
01010 xform->buffer = g_realloc (xform->buffer,
01011 xform->buffersize);
01012 }
01013
01014 g_memmove (xform->buffer + xform->buffered, buf + read, res);
01015 xform->buffered += res;
01016 break;
01017 }
01018 read += res;
01019 }
01020 }
01021
01022 return read;
01023 }
01024
01025 gint64
01026 xmms_xform_this_seek (xmms_xform_t *xform, gint64 offset,
01027 xmms_xform_seek_mode_t whence, xmms_error_t *err)
01028 {
01029 gint64 res;
01030
01031 if (xform->error) {
01032 xmms_error_set (err, XMMS_ERROR_GENERIC, "Seek on errored xform");
01033 return -1;
01034 }
01035
01036 if (!xform->plugin->methods.seek) {
01037 XMMS_DBG ("Seek not implemented in '%s'", xmms_xform_shortname (xform));
01038 xmms_error_set (err, XMMS_ERROR_GENERIC, "Seek not implemented");
01039 return -1;
01040 }
01041
01042 if (xform->buffered && whence == XMMS_XFORM_SEEK_CUR) {
01043 offset -= xform->buffered;
01044 }
01045
01046 res = xform->plugin->methods.seek (xform, offset, whence, err);
01047 if (res != -1) {
01048 xmms_xform_hotspot_t *hs;
01049
01050 xform->eos = FALSE;
01051 xform->buffered = 0;
01052
01053
01054 while ((hs = g_queue_pop_head (xform->hotspots)) != NULL) {
01055 g_free (hs->key);
01056 xmmsv_unref (hs->obj);
01057 g_free (hs);
01058 }
01059 }
01060
01061 return res;
01062 }
01063
01064 gint
01065 xmms_xform_peek (xmms_xform_t *xform, gpointer buf, gint siz,
01066 xmms_error_t *err)
01067 {
01068 g_return_val_if_fail (xform->prev, -1);
01069 return xmms_xform_this_peek (xform->prev, buf, siz, err);
01070 }
01071
01072 gchar *
01073 xmms_xform_read_line (xmms_xform_t *xform, gchar *line, xmms_error_t *err)
01074 {
01075 gchar *p;
01076
01077 g_return_val_if_fail (xform, NULL);
01078 g_return_val_if_fail (line, NULL);
01079
01080 p = strchr (xform->lr.buf, '\n');
01081
01082 if (!p) {
01083 gint l, r;
01084
01085 l = (XMMS_XFORM_MAX_LINE_SIZE - 1) - (xform->lr.bufend - xform->lr.buf);
01086 if (l) {
01087 r = xmms_xform_read (xform, xform->lr.bufend, l, err);
01088 if (r < 0) {
01089 return NULL;
01090 }
01091 xform->lr.bufend += r;
01092 }
01093 if (xform->lr.bufend <= xform->lr.buf)
01094 return NULL;
01095
01096 *(xform->lr.bufend) = '\0';
01097 p = strchr (xform->lr.buf, '\n');
01098 if (!p) {
01099 p = xform->lr.bufend;
01100 }
01101 }
01102
01103 if (p > xform->lr.buf && *(p-1) == '\r') {
01104 *(p-1) = '\0';
01105 } else {
01106 *p = '\0';
01107 }
01108
01109 strcpy (line, xform->lr.buf);
01110 memmove (xform->lr.buf, p + 1, xform->lr.bufend - p);
01111 xform->lr.bufend -= (p - xform->lr.buf) + 1;
01112 *xform->lr.bufend = '\0';
01113
01114 return line;
01115 }
01116
01117 gint
01118 xmms_xform_read (xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
01119 {
01120 g_return_val_if_fail (xform->prev, -1);
01121 return xmms_xform_this_read (xform->prev, buf, siz, err);
01122 }
01123
01124 gint64
01125 xmms_xform_seek (xmms_xform_t *xform, gint64 offset,
01126 xmms_xform_seek_mode_t whence, xmms_error_t *err)
01127 {
01128 g_return_val_if_fail (xform->prev, -1);
01129 return xmms_xform_this_seek (xform->prev, offset, whence, err);
01130 }
01131
01132 const gchar *
01133 xmms_xform_get_url (xmms_xform_t *xform)
01134 {
01135 const gchar *url = NULL;
01136 xmms_xform_t *x;
01137 x = xform;
01138
01139 while (!url && x) {
01140 url = xmms_xform_indata_get_str (x, XMMS_STREAM_TYPE_URL);
01141 x = x->prev;
01142 }
01143
01144 return url;
01145 }
01146
01147 static void
01148 xmms_xform_plugin_destroy (xmms_object_t *obj)
01149 {
01150 xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *)obj;
01151
01152 while (plugin->in_types) {
01153 xmms_object_unref (plugin->in_types->data);
01154
01155 plugin->in_types = g_list_delete_link (plugin->in_types,
01156 plugin->in_types);
01157 }
01158
01159 xmms_plugin_destroy ((xmms_plugin_t *)obj);
01160 }
01161
01162 xmms_plugin_t *
01163 xmms_xform_plugin_new (void)
01164 {
01165 xmms_xform_plugin_t *res;
01166
01167 res = xmms_object_new (xmms_xform_plugin_t, xmms_xform_plugin_destroy);
01168
01169 return (xmms_plugin_t *)res;
01170 }
01171
01172 void
01173 xmms_xform_plugin_methods_set (xmms_xform_plugin_t *plugin,
01174 xmms_xform_methods_t *methods)
01175 {
01176
01177 g_return_if_fail (plugin);
01178 g_return_if_fail (plugin->plugin.type == XMMS_PLUGIN_TYPE_XFORM);
01179
01180 XMMS_DBG ("Registering xform '%s'",
01181 xmms_plugin_shortname_get ((xmms_plugin_t *) plugin));
01182
01183 memcpy (&plugin->methods, methods, sizeof (xmms_xform_methods_t));
01184 }
01185
01186 gboolean
01187 xmms_xform_plugin_verify (xmms_plugin_t *_plugin)
01188 {
01189 xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *) _plugin;
01190
01191 g_return_val_if_fail (plugin, FALSE);
01192 g_return_val_if_fail (plugin->plugin.type == XMMS_PLUGIN_TYPE_XFORM, FALSE);
01193
01194
01195
01196 return TRUE;
01197 }
01198
01199 void
01200 xmms_xform_plugin_indata_add (xmms_xform_plugin_t *plugin, ...)
01201 {
01202 xmms_stream_type_t *t;
01203 va_list ap;
01204 gchar *config_key, config_value[32];
01205 gint priority;
01206
01207 va_start (ap, plugin);
01208 t = xmms_stream_type_parse (ap);
01209 va_end (ap);
01210
01211 config_key = g_strconcat ("priority.",
01212 xmms_stream_type_get_str (t, XMMS_STREAM_TYPE_NAME),
01213 NULL);
01214 priority = xmms_stream_type_get_int (t, XMMS_STREAM_TYPE_PRIORITY);
01215 g_snprintf (config_value, sizeof (config_value), "%d", priority);
01216 xmms_xform_plugin_config_property_register (plugin, config_key,
01217 config_value, NULL, NULL);
01218 g_free (config_key);
01219
01220 plugin->in_types = g_list_prepend (plugin->in_types, t);
01221 }
01222
01223 static gboolean
01224 xmms_xform_plugin_supports (xmms_xform_plugin_t *plugin, xmms_stream_type_t *st,
01225 gint *priority)
01226 {
01227 GList *t;
01228
01229 for (t = plugin->in_types; t; t = g_list_next (t)) {
01230 if (xmms_stream_type_match (t->data, st)) {
01231 if (priority) {
01232 gchar *config_key;
01233 xmms_config_property_t *conf_priority;
01234
01235 config_key = g_strconcat ("priority.",
01236 xmms_stream_type_get_str (t->data, XMMS_STREAM_TYPE_NAME),
01237 NULL);
01238 conf_priority = xmms_plugin_config_lookup ((xmms_plugin_t *)plugin,
01239 config_key);
01240 g_free (config_key);
01241
01242 if (conf_priority) {
01243 *priority = xmms_config_property_get_int (conf_priority);
01244 } else {
01245 *priority = XMMS_STREAM_TYPE_PRIORITY_DEFAULT;
01246 }
01247 }
01248 return TRUE;
01249 }
01250 }
01251 return FALSE;
01252 }
01253
01254 typedef struct match_state_St {
01255 xmms_xform_plugin_t *match;
01256 xmms_stream_type_t *out_type;
01257 gint priority;
01258 } match_state_t;
01259
01260 static gboolean
01261 xmms_xform_match (xmms_plugin_t *_plugin, gpointer user_data)
01262 {
01263 xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *)_plugin;
01264 match_state_t *state = (match_state_t *)user_data;
01265 gint priority;
01266
01267 g_assert (_plugin->type == XMMS_PLUGIN_TYPE_XFORM);
01268
01269 if (!plugin->in_types) {
01270 XMMS_DBG ("Skipping plugin '%s'", xmms_plugin_shortname_get (_plugin));
01271 return TRUE;
01272 }
01273
01274 XMMS_DBG ("Trying plugin '%s'", xmms_plugin_shortname_get (_plugin));
01275 if (xmms_xform_plugin_supports (plugin, state->out_type, &priority)) {
01276 XMMS_DBG ("Plugin '%s' matched (priority %d)",
01277 xmms_plugin_shortname_get (_plugin), priority);
01278 if (priority > state->priority) {
01279 if (state->match) {
01280 XMMS_DBG ("Using plugin '%s' (priority %d) instead of '%s' (priority %d)",
01281 xmms_plugin_shortname_get (_plugin), priority,
01282 xmms_plugin_shortname_get ((xmms_plugin_t *)state->match),
01283 state->priority);
01284 }
01285
01286 state->match = plugin;
01287 state->priority = priority;
01288 }
01289 }
01290
01291 return TRUE;
01292 }
01293
01294 xmms_xform_t *
01295 xmms_xform_find (xmms_xform_t *prev, xmms_medialib_entry_t entry,
01296 GList *goal_hints)
01297 {
01298 match_state_t state;
01299 xmms_xform_t *xform = NULL;
01300
01301 state.out_type = prev->out_type;
01302 state.match = NULL;
01303 state.priority = -1;
01304
01305 xmms_plugin_foreach (XMMS_PLUGIN_TYPE_XFORM, xmms_xform_match, &state);
01306
01307 if (state.match) {
01308 xform = xmms_xform_new (state.match, prev, entry, goal_hints);
01309 } else {
01310 XMMS_DBG ("Found no matching plugin...");
01311 }
01312
01313 return xform;
01314 }
01315
01316 gboolean
01317 xmms_xform_iseos (xmms_xform_t *xform)
01318 {
01319 gboolean ret = TRUE;
01320
01321 if (xform->prev) {
01322 ret = xform->prev->eos;
01323 }
01324
01325 return ret;
01326 }
01327
01328 const xmms_stream_type_t *
01329 xmms_xform_get_out_stream_type (xmms_xform_t *xform)
01330 {
01331 return xform->out_type;
01332 }
01333
01334 const GList *
01335 xmms_xform_goal_hints_get (xmms_xform_t *xform)
01336 {
01337 return xform->goal_hints;
01338 }
01339
01340
01341 static gboolean
01342 has_goalformat (xmms_xform_t *xform, GList *goal_formats)
01343 {
01344 const xmms_stream_type_t *current;
01345 gboolean ret = FALSE;
01346 GList *n;
01347
01348 current = xmms_xform_get_out_stream_type (xform);
01349
01350 for (n = goal_formats; n; n = g_list_next (n)) {
01351 xmms_stream_type_t *goal_type = n->data;
01352 if (xmms_stream_type_match (goal_type, current)) {
01353 ret = TRUE;
01354 break;
01355 }
01356
01357 }
01358
01359 if (!ret) {
01360 XMMS_DBG ("Not in one of %d goal-types", g_list_length (goal_formats));
01361 }
01362
01363 return ret;
01364 }
01365
01366 static void
01367 outdata_type_metadata_collect (xmms_xform_t *xform)
01368 {
01369 gint val;
01370 const char *mime;
01371 xmms_stream_type_t *type;
01372
01373 type = xform->out_type;
01374 mime = xmms_stream_type_get_str (type, XMMS_STREAM_TYPE_MIMETYPE);
01375 if (strcmp (mime, "audio/pcm") != 0) {
01376 return;
01377 }
01378
01379 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_FORMAT);
01380 if (val != -1) {
01381 const gchar *name = xmms_sample_name_get ((xmms_sample_format_t) val);
01382 xmms_xform_metadata_set_str (xform,
01383 XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLE_FMT,
01384 name);
01385 }
01386
01387 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
01388 if (val != -1) {
01389 xmms_xform_metadata_set_int (xform,
01390 XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE,
01391 val);
01392 }
01393
01394 val = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_CHANNELS);
01395 if (val != -1) {
01396 xmms_xform_metadata_set_int (xform,
01397 XMMS_MEDIALIB_ENTRY_PROPERTY_CHANNELS,
01398 val);
01399 }
01400 }
01401
01402 static xmms_xform_t *
01403 chain_setup (xmms_medialib_entry_t entry, const gchar *url, GList *goal_formats)
01404 {
01405 xmms_xform_t *xform, *last;
01406 gchar *durl, *args;
01407
01408 if (!entry) {
01409 entry = 1;
01410 }
01411
01412 xform = xmms_xform_new (NULL, NULL, 0, goal_formats);
01413
01414 durl = g_strdup (url);
01415
01416 args = strchr (durl, '?');
01417 if (args) {
01418 gchar **params;
01419 gint i;
01420 *args = 0;
01421 args++;
01422 xmms_medialib_decode_url (args);
01423
01424 params = g_strsplit (args, "&", 0);
01425
01426 for (i = 0; params && params[i]; i++) {
01427 gchar *v;
01428 v = strchr (params[i], '=');
01429 if (v) {
01430 *v = 0;
01431 v++;
01432 xmms_xform_metadata_set_str (xform, params[i], v);
01433 } else {
01434 xmms_xform_metadata_set_int (xform, params[i], 1);
01435 }
01436 }
01437 g_strfreev (params);
01438 }
01439 xmms_medialib_decode_url (durl);
01440
01441 xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE,
01442 "application/x-url", XMMS_STREAM_TYPE_URL,
01443 durl, XMMS_STREAM_TYPE_END);
01444
01445 g_free (durl);
01446
01447 last = xform;
01448
01449 do {
01450 xform = xmms_xform_find (last, entry, goal_formats);
01451 if (!xform) {
01452 xmms_log_error ("Couldn't set up chain for '%s' (%d)",
01453 url, entry);
01454 xmms_object_unref (last);
01455
01456 return NULL;
01457 }
01458 xmms_object_unref (last);
01459 last = xform;
01460 } while (!has_goalformat (xform, goal_formats));
01461
01462 outdata_type_metadata_collect (last);
01463
01464 return last;
01465 }
01466
01467 static void
01468 chain_finalize (xmms_xform_t *xform, xmms_medialib_entry_t entry,
01469 const gchar *url, gboolean rehashing)
01470 {
01471 GString *namestr;
01472
01473 namestr = g_string_new ("");
01474 xmms_xform_metadata_collect (xform, namestr, rehashing);
01475 xmms_log_info ("Successfully setup chain for '%s' (%d) containing %s",
01476 url, entry, namestr->str);
01477
01478 g_string_free (namestr, TRUE);
01479 }
01480
01481 static gchar *
01482 get_url_for_entry (xmms_medialib_entry_t entry)
01483 {
01484 xmms_medialib_session_t *session;
01485 gchar *url = NULL;
01486
01487 session = xmms_medialib_begin ();
01488 url = xmms_medialib_entry_property_get_str (session, entry,
01489 XMMS_MEDIALIB_ENTRY_PROPERTY_URL);
01490 xmms_medialib_end (session);
01491
01492 if (!url) {
01493 xmms_log_error ("Couldn't get url for entry (%d)", entry);
01494 }
01495
01496 return url;
01497 }
01498
01499 xmms_xform_t *
01500 xmms_xform_chain_setup (xmms_medialib_entry_t entry, GList *goal_formats,
01501 gboolean rehash)
01502 {
01503 gchar *url;
01504 xmms_xform_t *xform;
01505
01506 if (!(url = get_url_for_entry (entry))) {
01507 return NULL;
01508 }
01509
01510 xform = xmms_xform_chain_setup_url (entry, url, goal_formats, rehash);
01511 g_free (url);
01512
01513 return xform;
01514 }
01515
01516 xmms_xform_t *
01517 xmms_xform_chain_setup_url (xmms_medialib_entry_t entry, const gchar *url,
01518 GList *goal_formats, gboolean rehash)
01519 {
01520 xmms_xform_t *last;
01521 xmms_plugin_t *plugin;
01522 xmms_xform_plugin_t *xform_plugin;
01523 gboolean add_segment = FALSE;
01524
01525 last = chain_setup (entry, url, goal_formats);
01526 if (!last) {
01527 return NULL;
01528 }
01529
01530
01531 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, "segment");
01532 xform_plugin = (xmms_xform_plugin_t *) plugin;
01533
01534
01535
01536 if (xform_plugin) {
01537 add_segment = xmms_xform_plugin_supports (xform_plugin,
01538 last->out_type,
01539 NULL);
01540 xmms_object_unref (plugin);
01541 }
01542
01543
01544 if (add_segment) {
01545 last = xmms_xform_new_effect (last, entry, goal_formats, "segment");
01546 if (!last) {
01547 return NULL;
01548 }
01549 }
01550
01551
01552 if (!rehash) {
01553 last = add_effects (last, entry, goal_formats);
01554 if (!last) {
01555 return NULL;
01556 }
01557 }
01558
01559 chain_finalize (last, entry, url, rehash);
01560 return last;
01561 }
01562
01563 xmms_config_property_t *
01564 xmms_xform_plugin_config_property_register (xmms_xform_plugin_t *xform_plugin,
01565 const gchar *name,
01566 const gchar *default_value,
01567 xmms_object_handler_t cb,
01568 gpointer userdata)
01569 {
01570 xmms_plugin_t *plugin = (xmms_plugin_t *) xform_plugin;
01571
01572 return xmms_plugin_config_property_register (plugin, name,
01573 default_value,
01574 cb, userdata);
01575 }
01576
01577 xmms_config_property_t *
01578 xmms_xform_config_lookup (xmms_xform_t *xform, const gchar *path)
01579 {
01580 g_return_val_if_fail (xform->plugin, NULL);
01581
01582 return xmms_plugin_config_lookup ((xmms_plugin_t *) xform->plugin, path);
01583 }
01584
01585 static xmms_xform_t *
01586 add_effects (xmms_xform_t *last, xmms_medialib_entry_t entry,
01587 GList *goal_formats)
01588 {
01589 gint effect_no;
01590
01591 for (effect_no = 0; TRUE; effect_no++) {
01592 xmms_config_property_t *cfg;
01593 gchar key[64];
01594 const gchar *name;
01595
01596 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
01597
01598 cfg = xmms_config_lookup (key);
01599 if (!cfg) {
01600 break;
01601 }
01602
01603 name = xmms_config_property_get_string (cfg);
01604
01605 if (!name[0]) {
01606 continue;
01607 }
01608
01609 last = xmms_xform_new_effect (last, entry, goal_formats, name);
01610 }
01611
01612 return last;
01613 }
01614
01615 static xmms_xform_t *
01616 xmms_xform_new_effect (xmms_xform_t *last, xmms_medialib_entry_t entry,
01617 GList *goal_formats, const gchar *name)
01618 {
01619 xmms_plugin_t *plugin;
01620 xmms_xform_plugin_t *xform_plugin;
01621 xmms_xform_t *xform;
01622
01623 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01624 if (!plugin) {
01625 xmms_log_error ("Couldn't find any effect named '%s'", name);
01626 return last;
01627 }
01628
01629 xform_plugin = (xmms_xform_plugin_t *) plugin;
01630 if (!xmms_xform_plugin_supports (xform_plugin, last->out_type, NULL)) {
01631 xmms_log_info ("Effect '%s' doesn't support format, skipping",
01632 xmms_plugin_shortname_get (plugin));
01633 xmms_object_unref (plugin);
01634 return last;
01635 }
01636
01637 xform = xmms_xform_new (xform_plugin, last, entry, goal_formats);
01638
01639 if (xform) {
01640 xmms_object_unref (last);
01641 last = xform;
01642 } else {
01643 xmms_log_info ("Effect '%s' failed to initialize, skipping",
01644 xmms_plugin_shortname_get (plugin));
01645 }
01646 xmms_xform_plugin_config_property_register (xform_plugin,
01647 "enabled", "0",
01648 NULL, NULL);
01649 xmms_object_unref (plugin);
01650 return last;
01651 }
01652
01653 static void
01654 update_effect_properties (xmms_object_t *object, xmmsv_t *data,
01655 gpointer userdata)
01656 {
01657 gint effect_no = GPOINTER_TO_INT (userdata);
01658 const gchar *name;
01659
01660 xmms_config_property_t *cfg;
01661 xmms_xform_plugin_t *xform_plugin;
01662 xmms_plugin_t *plugin;
01663 gchar key[64];
01664
01665 name = xmms_config_property_get_string ((xmms_config_property_t *) object);
01666
01667 if (name[0]) {
01668 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01669 if (!plugin) {
01670 xmms_log_error ("Couldn't find any effect named '%s'", name);
01671 } else {
01672 xform_plugin = (xmms_xform_plugin_t *) plugin;
01673 xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
01674 "1", NULL, NULL);
01675 xmms_object_unref (plugin);
01676 }
01677
01678
01679 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no + 1);
01680
01681 cfg = xmms_config_lookup (key);
01682 if (!cfg) {
01683 xmms_config_property_register (key, "", update_effect_properties,
01684 GINT_TO_POINTER (effect_no + 1));
01685 }
01686 }
01687 }
01688
01689 static void
01690 effect_callbacks_init (void)
01691 {
01692 gint effect_no;
01693
01694 xmms_config_property_t *cfg;
01695 xmms_xform_plugin_t *xform_plugin;
01696 xmms_plugin_t *plugin;
01697 gchar key[64];
01698 const gchar *name;
01699
01700 for (effect_no = 0; ; effect_no++) {
01701 g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
01702
01703 cfg = xmms_config_lookup (key);
01704 if (!cfg) {
01705 break;
01706 }
01707 xmms_config_property_callback_set (cfg, update_effect_properties,
01708 GINT_TO_POINTER (effect_no));
01709
01710 name = xmms_config_property_get_string (cfg);
01711 if (!name[0]) {
01712 continue;
01713 }
01714
01715 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
01716 if (!plugin) {
01717 xmms_log_error ("Couldn't find any effect named '%s'", name);
01718 continue;
01719 }
01720
01721 xform_plugin = (xmms_xform_plugin_t *) plugin;
01722 xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
01723 "1", NULL, NULL);
01724
01725 xmms_object_unref (plugin);
01726 }
01727
01728
01729
01730 if ((!effect_no) || name[0]) {
01731 xmms_config_property_register (key, "", update_effect_properties,
01732 GINT_TO_POINTER (effect_no));
01733 }
01734 }
01735