XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2011 XMMS2 Team 00003 * 00004 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 */ 00016 00017 /** 00018 * @file 00019 * xforms 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 /** used for line reading */ 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); /* filenames can't contain '/', can they? */ 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 /* can't use g_build_filename as we need to preserve 00197 slashes stuff like file:/// */ 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 /* The 'destroy' method is not mandatory */ 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 /* times_played == -1 if we haven't played this entry yet. so after initial 00683 * metadata collection the mlib would have timesplayed = -1 if we didn't do 00684 * the following */ 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 /* privdata is always got from the previous xform */ 00796 xform = xform->prev; 00797 00798 /* check if we have unhandled current (pos 0) hotspots for this key */ 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 /* might have eosed */ 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 /* update hotspots */ 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 /* buffer edited, update hotspot positions */ 00966 g_queue_foreach (xform->hotspots, &xmms_xform_hotspot_callback, &read); 00967 00968 if (xform->buffered) { 00969 /* unless we are _peek:ing often 00970 this should be fine */ 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 /* flush the hotspot queue on seek */ 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; /* FIXME: this is soooo ugly, don't do this */ 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 /* first check that segment plugin is available in the system */ 01420 plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, "segment"); 01421 xform_plugin = (xmms_xform_plugin_t *) plugin; 01422 01423 /* if segment plugin input is the same as current output, include it 01424 * for collecting additional duration metadata on audio entries */ 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 /* add segment plugin to the chain if it can be added */ 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 /* if not rehashing, also initialize all the effect plugins */ 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 /* setup new effect.order.n */ 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 /* the name stored in the last present property was not "" or there was no 01605 last present property */ 01606 if ((!effect_no) || name[0]) { 01607 xmms_config_property_register (key, "", update_effect_properties, 01608 GINT_TO_POINTER (effect_no)); 01609 } 01610 } 01611