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