XMMS2
xform.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2009 XMMS2 Team
3  *
4  * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  */
16 
17 /**
18  * @file
19  * xforms
20  */
21 
22 #include <string.h>
23 
24 #include "xmmspriv/xmms_plugin.h"
25 #include "xmmspriv/xmms_xform.h"
27 #include "xmmspriv/xmms_medialib.h"
28 #include "xmmspriv/xmms_utils.h"
29 #include "xmms/xmms_ipc.h"
30 #include "xmms/xmms_log.h"
31 #include "xmms/xmms_object.h"
32 
33 struct xmms_xform_object_St {
34  xmms_object_t obj;
35 };
36 
37 struct xmms_xform_St {
38  xmms_object_t obj;
39  struct xmms_xform_St *prev;
40 
41  const xmms_xform_plugin_t *plugin;
43 
44  gboolean inited;
45 
46  void *priv;
47 
48  xmms_stream_type_t *out_type;
49 
50  GList *goal_hints;
51 
52  gboolean eos;
53  gboolean error;
54 
55  char *buffer;
56  gint buffered;
57  gint buffersize;
58 
59  gboolean metadata_collected;
60 
61  gboolean metadata_changed;
62  GHashTable *metadata;
63 
64  GHashTable *privdata;
65  GQueue *hotspots;
66 
67  GList *browse_list;
68  xmmsv_t *browse_dict;
69  gint browse_index;
70 
71  /** used for line reading */
72  struct {
73  gchar buf[XMMS_XFORM_MAX_LINE_SIZE];
74  gchar *bufend;
75  } lr;
76 };
77 
78 typedef struct xmms_xform_hotspot_St {
79  guint pos;
80  gchar *key;
81  xmmsv_t *obj;
83 
84 #define READ_CHUNK 4096
85 
86 struct xmms_xform_plugin_St {
87  xmms_plugin_t plugin;
88 
89  xmms_xform_methods_t methods;
90 
91  GList *in_types;
92 };
93 
95  GList *goal_hints);
96 const char *xmms_xform_shortname (xmms_xform_t *xform);
97 static xmms_xform_t *add_effects (xmms_xform_t *last,
99  GList *goal_formats);
100 static xmms_xform_t *xmms_xform_new_effect (xmms_xform_t* last,
101  xmms_medialib_entry_t entry,
102  GList *goal_formats,
103  const gchar *name);
104 static void xmms_xform_destroy (xmms_object_t *object);
105 static void effect_callbacks_init (void);
106 
107 void
109  const gchar *key,
110  const gchar *value)
111 {
112  xmmsv_t *val = xmmsv_new_string (value);
113  xmms_xform_browse_add_entry_property (xform, key, val);
114  xmmsv_unref (val);
115 }
116 
117 
118 void
120  const gchar *key,
121  gint value)
122 {
123  xmmsv_t *val = xmmsv_new_int (value);
124  xmms_xform_browse_add_entry_property (xform, key, val);
125  xmmsv_unref (val);
126 }
127 
128 void
129 xmms_xform_browse_add_symlink_args (xmms_xform_t *xform, const gchar *basename,
130  const gchar *url, gint nargs, gchar **args)
131 {
132  GString *s;
133  gchar *eurl;
134  gchar bname[32];
135  gint i;
136 
137  if (!basename) {
138  g_snprintf (bname, sizeof (bname), "%d", xform->browse_index++);
139  basename = bname;
140  }
141 
142  xmms_xform_browse_add_entry (xform, basename, 0);
143  eurl = xmms_medialib_url_encode (url);
144  s = g_string_new (eurl);
145 
146  for (i = 0; i < nargs; i++) {
147  g_string_append_c (s, i == 0 ? '?' : '&');
148  g_string_append (s, args[i]);
149  }
150 
151  xmms_xform_browse_add_entry_property_str (xform, "realpath", s->str);
152 
153  g_free (eurl);
154  g_string_free (s, TRUE);
155 }
156 
157 void
158 xmms_xform_browse_add_symlink (xmms_xform_t *xform, const gchar *basename,
159  const gchar *url)
160 {
161  xmms_xform_browse_add_symlink_args (xform, basename, url, 0, NULL);
162 }
163 
164 void
166  xmmsv_t *val)
167 {
168  g_return_if_fail (xform);
169  g_return_if_fail (xform->browse_dict);
170  g_return_if_fail (key);
171  g_return_if_fail (val);
172 
173  xmmsv_dict_set (xform->browse_dict, key, val);
174 }
175 
176 void
177 xmms_xform_browse_add_entry (xmms_xform_t *xform, const gchar *filename,
178  guint32 flags)
179 {
180  xmmsv_t *val;
181  const gchar *url;
182  gchar *efile, *eurl, *t;
183  gint l, isdir;
184 
185  g_return_if_fail (filename);
186 
187  t = strchr (filename, '/');
188  g_return_if_fail (!t); /* filenames can't contain '/', can they? */
189 
190  url = xmms_xform_get_url (xform);
191  g_return_if_fail (url);
192 
193  xform->browse_dict = xmmsv_new_dict ();
194 
195  eurl = xmms_medialib_url_encode (url);
196  efile = xmms_medialib_url_encode (filename);
197 
198  /* can't use g_build_filename as we need to preserve
199  slashes stuff like file:/// */
200  l = strlen (url);
201  if (l && url[l - 1] == '/') {
202  t = g_strdup_printf ("%s%s", eurl, efile);
203  } else {
204  t = g_strdup_printf ("%s/%s", eurl, efile);
205  }
206 
207  isdir = !!(flags & XMMS_XFORM_BROWSE_FLAG_DIR);
208  xmms_xform_browse_add_entry_property_str (xform, "path", t);
209  xmms_xform_browse_add_entry_property_int (xform, "isdir", isdir);
210 
211  val = xform->browse_dict;
212  xform->browse_list = g_list_prepend (xform->browse_list, val);
213 
214  g_free (t);
215  g_free (efile);
216  g_free (eurl);
217 }
218 
219 static gint
220 xmms_browse_list_sortfunc (gconstpointer a, gconstpointer b)
221 {
222  int r1, r2;
223  xmmsv_t *val1, *val2, *tmp1, *tmp2;
224  const gchar *s1, *s2;
225 
226  val1 = (xmmsv_t *) a;
227  val2 = (xmmsv_t *) b;
228 
229  g_return_val_if_fail (xmmsv_get_type (val1) == XMMSV_TYPE_DICT, 0);
230  g_return_val_if_fail (xmmsv_get_type (val2) == XMMSV_TYPE_DICT, 0);
231 
232  r1 = xmmsv_dict_get (val1, "intsort", &tmp1);
233  r2 = xmmsv_dict_get (val2, "intsort", &tmp2);
234 
235  if (r1 && r2) {
236  gint i1, i2;
237 
238  if (!xmmsv_get_int (tmp1, &i1))
239  return 0;
240  if (!xmmsv_get_int (tmp2, &i2))
241  return 0;
242  return i1 > i2;
243  }
244 
245  if (!xmmsv_dict_get (val1, "path", &tmp1))
246  return 0;
247  if (!xmmsv_dict_get (val2, "path", &tmp2))
248  return 0;
249 
250  if (!xmmsv_get_string (tmp1, &s1))
251  return 0;
252  if (!xmmsv_get_string (tmp2, &s2))
253  return 0;
254 
255  return xmms_natcmp (s1, s2);
256 }
257 
258 GList *
259 xmms_xform_browse_method (xmms_xform_t *xform, const gchar *url,
260  xmms_error_t *error)
261 {
262  GList *list = NULL;
263 
264  if (xform->plugin->methods.browse) {
265  if (!xform->plugin->methods.browse (xform, url, error)) {
266  return NULL;
267  }
268  list = xform->browse_list;
269  xform->browse_list = NULL;
270  list = g_list_sort (list, xmms_browse_list_sortfunc);
271  } else {
272  xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
273  }
274 
275  return list;
276 }
277 
278 GList *
279 xmms_xform_browse (const gchar *url, xmms_error_t *error)
280 {
281  GList *list = NULL;
282  gchar *durl;
283  xmms_xform_t *xform = NULL;
284  xmms_xform_t *xform2 = NULL;
285 
286  xform = xmms_xform_new (NULL, NULL, 0, NULL);
287 
288  durl = g_strdup (url);
290  XMMS_DBG ("url = %s", durl);
291 
294  "application/x-url",
296  durl,
298 
299  xform2 = xmms_xform_find (xform, 0, NULL);
300  if (xform2) {
301  XMMS_DBG ("found xform %s", xmms_xform_shortname (xform2));
302  } else {
303  xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL");
304  xmms_object_unref (xform);
305  g_free (durl);
306  return NULL;
307  }
308 
309  list = xmms_xform_browse_method (xform2, durl, error);
310 
311  xmms_object_unref (xform);
312  xmms_object_unref (xform2);
313 
314  g_free (durl);
315 
316  return list;
317 }
318 
319 static GList *
320 xmms_xform_client_browse (xmms_xform_object_t *obj, const gchar *url,
321  xmms_error_t *error)
322 {
323  return xmms_xform_browse (url, error);
324 }
325 XMMS_CMD_DEFINE (browse, xmms_xform_client_browse, xmms_xform_object_t *,
326  LIST, STRING, NONE);
327 
328 static void
329 xmms_xform_object_destroy (xmms_object_t *obj)
330 {
332 }
333 
336 {
337  xmms_xform_object_t *obj;
338 
339  obj = xmms_object_new (xmms_xform_object_t, xmms_xform_object_destroy);
340 
342 
344  XMMS_CMD_FUNC (browse));
345 
346  effect_callbacks_init ();
347 
348  return obj;
349 }
350 
351 static void
352 xmms_xform_destroy (xmms_object_t *object)
353 {
354  xmms_xform_t *xform = (xmms_xform_t *)object;
355 
356  XMMS_DBG ("Freeing xform '%s'", xmms_xform_shortname (xform));
357 
358  /* The 'destroy' method is not mandatory */
359  if (xform->plugin && xform->plugin->methods.destroy && xform->inited) {
360  xform->plugin->methods.destroy (xform);
361  }
362 
363  g_hash_table_destroy (xform->metadata);
364 
365  g_hash_table_destroy (xform->privdata);
366  g_queue_free (xform->hotspots);
367 
368  g_free (xform->buffer);
369 
370  xmms_object_unref (xform->out_type);
371  xmms_object_unref (xform->plugin);
372 
373  if (xform->prev) {
374  xmms_object_unref (xform->prev);
375  }
376 
377 }
378 
379 xmms_xform_t *
381  xmms_medialib_entry_t entry, GList *goal_hints)
382 {
383  xmms_xform_t *xform;
384 
385  xform = xmms_object_new (xmms_xform_t, xmms_xform_destroy);
386 
387  xmms_object_ref (plugin);
388  xform->plugin = plugin;
389  xform->entry = entry;
390  xform->goal_hints = goal_hints;
391  xform->lr.bufend = &xform->lr.buf[0];
392 
393  if (prev) {
394  xmms_object_ref (prev);
395  xform->prev = prev;
396  }
397 
398  xform->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
399  g_free,
400  (GDestroyNotify) xmmsv_unref);
401 
402  xform->privdata = g_hash_table_new_full (g_str_hash, g_str_equal,
403  g_free,
404  (GDestroyNotify) xmmsv_unref);
405  xform->hotspots = g_queue_new ();
406 
407  if (plugin && entry) {
408  if (!plugin->methods.init (xform)) {
409  xmms_object_unref (xform);
410  return NULL;
411  }
412  xform->inited = TRUE;
413  g_return_val_if_fail (xform->out_type, NULL);
414  }
415 
416  xform->buffer = g_malloc (READ_CHUNK);
417  xform->buffersize = READ_CHUNK;
418 
419  return xform;
420 }
421 
424 {
425  return xform->entry;
426 }
427 
428 gpointer
430 {
431  return xform->priv;
432 }
433 
434 void
436 {
437  xform->priv = data;
438 }
439 
440 void
442 {
443  va_list ap;
444  va_start (ap, xform);
445  xform->out_type = xmms_stream_type_parse (ap);
446  va_end (ap);
447 }
448 
449 void
451 {
452  xmms_object_ref (type);
453  xform->out_type = type;
454 }
455 
456 void
458 {
459  xmms_object_ref (xform->prev->out_type);
460  xform->out_type = xform->prev->out_type;
461 }
462 
463 const char *
465 {
466  const gchar *r;
467  r = xmms_stream_type_get_str (xform->prev->out_type, key);
468  if (r) {
469  return r;
470  } else if (xform->prev) {
471  return xmms_xform_indata_find_str (xform->prev, key);
472  }
473  return NULL;
474 }
475 
476 const char *
478 {
479  return xmms_stream_type_get_str (xform->prev->out_type, key);
480 }
481 
482 gint
484 {
485  return xmms_stream_type_get_int (xform->prev->out_type, key);
486 }
487 
490 {
491  return xform->out_type;
492 }
493 
496 {
497  return xmms_xform_outtype_get (xform->prev);
498 }
499 
500 
501 
502 const char *
504 {
505  return xmms_stream_type_get_str (xform->out_type, key);
506 }
507 
508 gint
510 {
511  return xmms_stream_type_get_int (xform->out_type, key);
512 }
513 
514 
515 void
516 xmms_xform_metadata_set_int (xmms_xform_t *xform, const char *key, int val)
517 {
518  XMMS_DBG ("Setting '%s' to %d", key, val);
519  g_hash_table_insert (xform->metadata, g_strdup (key),
520  xmmsv_new_int (val));
521  xform->metadata_changed = TRUE;
522 }
523 
524 void
525 xmms_xform_metadata_set_str (xmms_xform_t *xform, const char *key,
526  const char *val)
527 {
528  const char *old;
529 
530  if (!g_utf8_validate (val, -1, NULL)) {
531  xmms_log_error ("xform '%s' tried to set property '%s' to a NON UTF-8 string!", xmms_xform_shortname (xform), key);
532  return;
533  }
534 
535  if (xmms_xform_metadata_get_str (xform, key, &old)) {
536  if (strcmp (old, val) == 0) {
537  return;
538  }
539  }
540 
541  g_hash_table_insert (xform->metadata, g_strdup (key),
542  xmmsv_new_string (val));
543 
544  xform->metadata_changed = TRUE;
545 }
546 
547 static const xmmsv_t *
548 xmms_xform_metadata_get_val (xmms_xform_t *xform, const char *key)
549 {
550  xmmsv_t *val = NULL;
551 
552  for (; xform; xform = xform->prev) {
553  val = g_hash_table_lookup (xform->metadata, key);
554  if (val) {
555  break;
556  }
557  }
558 
559  return val;
560 }
561 
562 gboolean
563 xmms_xform_metadata_has_val (xmms_xform_t *xform, const gchar *key)
564 {
565  return !!xmms_xform_metadata_get_val (xform, key);
566 }
567 
568 gboolean
569 xmms_xform_metadata_get_int (xmms_xform_t *xform, const char *key,
570  gint32 *val)
571 {
572  const xmmsv_t *obj;
573  gboolean ret = FALSE;
574 
575  obj = xmms_xform_metadata_get_val (xform, key);
576  if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) {
577  xmmsv_get_int (obj, val);
578  ret = TRUE;
579  }
580 
581  return ret;
582 }
583 
584 gboolean
585 xmms_xform_metadata_get_str (xmms_xform_t *xform, const char *key,
586  const gchar **val)
587 {
588  const xmmsv_t *obj;
589  gboolean ret = FALSE;
590 
591  obj = xmms_xform_metadata_get_val (xform, key);
592  if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) {
593  xmmsv_get_string (obj, val);
594  ret = TRUE;
595  }
596 
597  return ret;
598 }
599 
600 typedef struct {
601  xmms_medialib_session_t *session;
602  xmms_medialib_entry_t entry;
603  guint32 source;
604 } metadata_festate_t;
605 
606 static void
607 add_metadatum (gpointer _key, gpointer _value, gpointer user_data)
608 {
609  xmmsv_t *value = (xmmsv_t *) _value;
610  gchar *key = (gchar *) _key;
611  metadata_festate_t *st = (metadata_festate_t *) user_data;
612 
613  if (xmmsv_get_type (value) == XMMSV_TYPE_STRING) {
614  const gchar *s;
615  xmmsv_get_string (value, &s);
617  st->entry,
618  key,
619  s,
620  st->source);
621  } else if (xmmsv_get_type (value) == XMMSV_TYPE_INT32) {
622  gint i;
623  xmmsv_get_int (value, &i);
625  st->entry,
626  key,
627  i,
628  st->source);
629  } else {
630  XMMS_DBG ("Unknown type?!?");
631  }
632 }
633 
634 static void
635 xmms_xform_metadata_collect_one (xmms_xform_t *xform, metadata_festate_t *info)
636 {
637  gchar src[XMMS_PLUGIN_SHORTNAME_MAX_LEN + 8];
638 
639  XMMS_DBG ("Collecting metadata from %s", xmms_xform_shortname (xform));
640 
641  g_snprintf (src, sizeof (src), "plugin/%s",
642  xmms_xform_shortname (xform));
643 
644  info->source = xmms_medialib_source_to_id (info->session, src);
645  g_hash_table_foreach (xform->metadata, add_metadatum, info);
646 
647  xform->metadata_changed = FALSE;
648 }
649 
650 static void
651 xmms_xform_metadata_collect_r (xmms_xform_t *xform, metadata_festate_t *info,
652  GString *namestr)
653 {
654  if (xform->prev) {
655  xmms_xform_metadata_collect_r (xform->prev, info, namestr);
656  }
657 
658  if (xform->plugin) {
659  if (namestr->len) {
660  g_string_append_c (namestr, ':');
661  }
662  g_string_append (namestr, xmms_xform_shortname (xform));
663  }
664 
665  if (xform->metadata_changed) {
666  xmms_xform_metadata_collect_one (xform, info);
667  }
668 
669  xform->metadata_collected = TRUE;
670 }
671 
672 static void
673 xmms_xform_metadata_collect (xmms_xform_t *start, GString *namestr, gboolean rehashing)
674 {
675  metadata_festate_t info;
676  gint times_played;
677  gint last_started;
678  GTimeVal now;
679 
680  info.entry = start->entry;
681  info.session = xmms_medialib_begin_write ();
682 
683  times_played = xmms_medialib_entry_property_get_int (info.session,
684  info.entry,
686 
687  /* times_played == -1 if we haven't played this entry yet. so after initial
688  * metadata collection the mlib would have timesplayed = -1 if we didn't do
689  * the following */
690  if (times_played < 0) {
691  times_played = 0;
692  }
693 
694  last_started = xmms_medialib_entry_property_get_int (info.session,
695  info.entry,
697 
698  xmms_medialib_entry_cleanup (info.session, info.entry);
699 
700  xmms_xform_metadata_collect_r (start, &info, namestr);
701 
702  xmms_medialib_entry_property_set_str (info.session, info.entry,
704  namestr->str);
705 
706  xmms_medialib_entry_property_set_int (info.session, info.entry,
708  times_played + (rehashing ? 0 : 1));
709 
710  if (!rehashing || (rehashing && last_started)) {
711  g_get_current_time (&now);
712 
713  xmms_medialib_entry_property_set_int (info.session, info.entry,
715  (rehashing ? last_started : now.tv_sec));
716  }
717 
718  xmms_medialib_entry_status_set (info.session, info.entry,
720 
721  xmms_medialib_end (info.session);
722  xmms_medialib_entry_send_update (info.entry);
723 }
724 
725 static void
726 xmms_xform_metadata_update (xmms_xform_t *xform)
727 {
728  metadata_festate_t info;
729 
730  info.entry = xform->entry;
731  info.session = xmms_medialib_begin_write ();
732 
733  xmms_xform_metadata_collect_one (xform, &info);
734 
735  xmms_medialib_end (info.session);
736  xmms_medialib_entry_send_update (info.entry);
737 }
738 
739 static void
740 xmms_xform_auxdata_set_val (xmms_xform_t *xform, char *key, xmmsv_t *val)
741 {
743 
744  hs = g_new0 (xmms_xform_hotspot_t, 1);
745  hs->pos = xform->buffered;
746  hs->key = key;
747  hs->obj = val;
748 
749  g_queue_push_tail (xform->hotspots, hs);
750 }
751 
752 void
754 {
755  xmmsv_t *val = xmmsv_new_none ();
756  xmms_xform_auxdata_set_val (xform, NULL, val);
757 }
758 
759 void
760 xmms_xform_auxdata_set_int (xmms_xform_t *xform, const char *key, int intval)
761 {
762  xmmsv_t *val = xmmsv_new_int (intval);
763  xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
764 }
765 
766 void
767 xmms_xform_auxdata_set_str (xmms_xform_t *xform, const gchar *key,
768  const gchar *strval)
769 {
770  xmmsv_t *val;
771  const char *old;
772 
773  if (xmms_xform_auxdata_get_str (xform, key, &old)) {
774  if (strcmp (old, strval) == 0) {
775  return;
776  }
777  }
778 
779  val = xmmsv_new_string (strval);
780  xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
781 }
782 
783 void
784 xmms_xform_auxdata_set_bin (xmms_xform_t *xform, const gchar *key,
785  gpointer data, gssize len)
786 {
787  xmmsv_t *val;
788 
789  val = xmmsv_new_bin (data, len);
790  xmms_xform_auxdata_set_val (xform, g_strdup (key), val);
791 }
792 
793 static const xmmsv_t *
794 xmms_xform_auxdata_get_val (xmms_xform_t *xform, const gchar *key)
795 {
796  guint i;
798  xmmsv_t *val = NULL;
799 
800  /* privdata is always got from the previous xform */
801  xform = xform->prev;
802 
803  /* check if we have unhandled current (pos 0) hotspots for this key */
804  for (i=0; (hs = g_queue_peek_nth (xform->hotspots, i)) != NULL; i++) {
805  if (hs->pos != 0) {
806  break;
807  } else if (hs->key && !strcmp (key, hs->key)) {
808  val = hs->obj;
809  }
810  }
811 
812  if (!val) {
813  val = g_hash_table_lookup (xform->privdata, key);
814  }
815 
816  return val;
817 }
818 
819 gboolean
820 xmms_xform_auxdata_has_val (xmms_xform_t *xform, const gchar *key)
821 {
822  return !!xmms_xform_auxdata_get_val (xform, key);
823 }
824 
825 gboolean
826 xmms_xform_auxdata_get_int (xmms_xform_t *xform, const gchar *key, gint32 *val)
827 {
828  const xmmsv_t *obj;
829 
830  obj = xmms_xform_auxdata_get_val (xform, key);
831  if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) {
832  xmmsv_get_int (obj, val);
833  return TRUE;
834  }
835 
836  return FALSE;
837 }
838 
839 gboolean
840 xmms_xform_auxdata_get_str (xmms_xform_t *xform, const gchar *key,
841  const gchar **val)
842 {
843  const xmmsv_t *obj;
844 
845  obj = xmms_xform_auxdata_get_val (xform, key);
846  if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) {
847  xmmsv_get_string (obj, val);
848  return TRUE;
849  }
850 
851  return FALSE;
852 }
853 
854 gboolean
855 xmms_xform_auxdata_get_bin (xmms_xform_t *xform, const gchar *key,
856  const guchar **data, gsize *datalen)
857 {
858  const xmmsv_t *obj;
859 
860  obj = xmms_xform_auxdata_get_val (xform, key);
861  if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_BIN) {
862  xmmsv_get_bin (obj, data, datalen);
863  return TRUE;
864  }
865 
866  return FALSE;
867 }
868 
869 const char *
871 {
872  return (xform->plugin)
873  ? xmms_plugin_shortname_get ((xmms_plugin_t *) xform->plugin)
874  : "unknown";
875 }
876 
877 static gint
878 xmms_xform_this_peek (xmms_xform_t *xform, gpointer buf, gint siz,
879  xmms_error_t *err)
880 {
881  while (xform->buffered < siz) {
882  gint res;
883 
884  if (xform->buffered + READ_CHUNK > xform->buffersize) {
885  xform->buffersize *= 2;
886  xform->buffer = g_realloc (xform->buffer, xform->buffersize);
887  }
888 
889  res = xform->plugin->methods.read (xform,
890  &xform->buffer[xform->buffered],
891  READ_CHUNK, err);
892 
893  if (res < -1) {
894  XMMS_DBG ("Read method of %s returned bad value (%d) - BUG IN PLUGIN",
895  xmms_xform_shortname (xform), res);
896  res = -1;
897  }
898 
899  if (res == 0) {
900  xform->eos = TRUE;
901  break;
902  } else if (res == -1) {
903  xform->error = TRUE;
904  return -1;
905  } else {
906  xform->buffered += res;
907  }
908  }
909 
910  /* might have eosed */
911  siz = MIN (siz, xform->buffered);
912  memcpy (buf, xform->buffer, siz);
913  return siz;
914 }
915 
916 static void
917 xmms_xform_hotspot_callback (gpointer data, gpointer user_data)
918 {
919  xmms_xform_hotspot_t *hs = data;
920  gint *read = user_data;
921 
922  hs->pos -= *read;
923 }
924 
925 static gint
926 xmms_xform_hotspots_update (xmms_xform_t *xform)
927 {
929  gint ret = -1;
930 
931  hs = g_queue_peek_head (xform->hotspots);
932  while (hs != NULL && hs->pos == 0) {
933  g_queue_pop_head (xform->hotspots);
934  if (hs->key) {
935  g_hash_table_insert (xform->privdata, hs->key, hs->obj);
936  }
937  hs = g_queue_peek_head (xform->hotspots);
938  }
939 
940  if (hs != NULL) {
941  ret = hs->pos;
942  }
943 
944  return ret;
945 }
946 
947 gint
948 xmms_xform_this_read (xmms_xform_t *xform, gpointer buf, gint siz,
949  xmms_error_t *err)
950 {
951  gint read = 0;
952  gint nexths;
953 
954  if (xform->error) {
955  xmms_error_set (err, XMMS_ERROR_GENERIC, "Read on errored xform");
956  return -1;
957  }
958 
959  /* update hotspots */
960  nexths = xmms_xform_hotspots_update (xform);
961  if (nexths >= 0) {
962  siz = MIN (siz, nexths);
963  }
964 
965  if (xform->buffered) {
966  read = MIN (siz, xform->buffered);
967  memcpy (buf, xform->buffer, read);
968  xform->buffered -= read;
969 
970  /* buffer edited, update hotspot positions */
971  g_queue_foreach (xform->hotspots, &xmms_xform_hotspot_callback, &read);
972 
973  if (xform->buffered) {
974  /* unless we are _peek:ing often
975  this should be fine */
976  memmove (xform->buffer, &xform->buffer[read], xform->buffered);
977  }
978  }
979 
980  if (xform->eos) {
981  return read;
982  }
983 
984  while (read < siz) {
985  gint res;
986 
987  res = xform->plugin->methods.read (xform, buf + read, siz - read, err);
988  if (xform->metadata_collected && xform->metadata_changed)
989  xmms_xform_metadata_update (xform);
990 
991  if (res < -1) {
992  XMMS_DBG ("Read method of %s returned bad value (%d) - BUG IN PLUGIN", xmms_xform_shortname (xform), res);
993  res = -1;
994  }
995 
996  if (res == 0) {
997  xform->eos = TRUE;
998  break;
999  } else if (res == -1) {
1000  xform->error = TRUE;
1001  return -1;
1002  } else {
1003  if (read == 0)
1004  xmms_xform_hotspots_update (xform);
1005 
1006  if (!g_queue_is_empty (xform->hotspots)) {
1007  if (xform->buffered + res > xform->buffersize) {
1008  xform->buffersize = MAX (xform->buffersize * 2,
1009  xform->buffersize + res);
1010  xform->buffer = g_realloc (xform->buffer,
1011  xform->buffersize);
1012  }
1013 
1014  g_memmove (xform->buffer + xform->buffered, buf + read, res);
1015  xform->buffered += res;
1016  break;
1017  }
1018  read += res;
1019  }
1020  }
1021 
1022  return read;
1023 }
1024 
1025 gint64
1026 xmms_xform_this_seek (xmms_xform_t *xform, gint64 offset,
1027  xmms_xform_seek_mode_t whence, xmms_error_t *err)
1028 {
1029  gint64 res;
1030 
1031  if (xform->error) {
1032  xmms_error_set (err, XMMS_ERROR_GENERIC, "Seek on errored xform");
1033  return -1;
1034  }
1035 
1036  if (!xform->plugin->methods.seek) {
1037  XMMS_DBG ("Seek not implemented in '%s'", xmms_xform_shortname (xform));
1038  xmms_error_set (err, XMMS_ERROR_GENERIC, "Seek not implemented");
1039  return -1;
1040  }
1041 
1042  if (xform->buffered && whence == XMMS_XFORM_SEEK_CUR) {
1043  offset -= xform->buffered;
1044  }
1045 
1046  res = xform->plugin->methods.seek (xform, offset, whence, err);
1047  if (res != -1) {
1049 
1050  xform->eos = FALSE;
1051  xform->buffered = 0;
1052 
1053  /* flush the hotspot queue on seek */
1054  while ((hs = g_queue_pop_head (xform->hotspots)) != NULL) {
1055  g_free (hs->key);
1056  xmmsv_unref (hs->obj);
1057  g_free (hs);
1058  }
1059  }
1060 
1061  return res;
1062 }
1063 
1064 gint
1065 xmms_xform_peek (xmms_xform_t *xform, gpointer buf, gint siz,
1066  xmms_error_t *err)
1067 {
1068  g_return_val_if_fail (xform->prev, -1);
1069  return xmms_xform_this_peek (xform->prev, buf, siz, err);
1070 }
1071 
1072 gchar *
1074 {
1075  gchar *p;
1076 
1077  g_return_val_if_fail (xform, NULL);
1078  g_return_val_if_fail (line, NULL);
1079 
1080  p = strchr (xform->lr.buf, '\n');
1081 
1082  if (!p) {
1083  gint l, r;
1084 
1085  l = (XMMS_XFORM_MAX_LINE_SIZE - 1) - (xform->lr.bufend - xform->lr.buf);
1086  if (l) {
1087  r = xmms_xform_read (xform, xform->lr.bufend, l, err);
1088  if (r < 0) {
1089  return NULL;
1090  }
1091  xform->lr.bufend += r;
1092  }
1093  if (xform->lr.bufend <= xform->lr.buf)
1094  return NULL;
1095 
1096  *(xform->lr.bufend) = '\0';
1097  p = strchr (xform->lr.buf, '\n');
1098  if (!p) {
1099  p = xform->lr.bufend;
1100  }
1101  }
1102 
1103  if (p > xform->lr.buf && *(p-1) == '\r') {
1104  *(p-1) = '\0';
1105  } else {
1106  *p = '\0';
1107  }
1108 
1109  strcpy (line, xform->lr.buf);
1110  memmove (xform->lr.buf, p + 1, xform->lr.bufend - p);
1111  xform->lr.bufend -= (p - xform->lr.buf) + 1;
1112  *xform->lr.bufend = '\0';
1113 
1114  return line;
1115 }
1116 
1117 gint
1118 xmms_xform_read (xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
1119 {
1120  g_return_val_if_fail (xform->prev, -1);
1121  return xmms_xform_this_read (xform->prev, buf, siz, err);
1122 }
1123 
1124 gint64
1125 xmms_xform_seek (xmms_xform_t *xform, gint64 offset,
1126  xmms_xform_seek_mode_t whence, xmms_error_t *err)
1127 {
1128  g_return_val_if_fail (xform->prev, -1);
1129  return xmms_xform_this_seek (xform->prev, offset, whence, err);
1130 }
1131 
1132 const gchar *
1134 {
1135  const gchar *url = NULL;
1136  xmms_xform_t *x;
1137  x = xform;
1138 
1139  while (!url && x) {
1141  x = x->prev;
1142  }
1143 
1144  return url;
1145 }
1146 
1147 static void
1148 xmms_xform_plugin_destroy (xmms_object_t *obj)
1149 {
1150  xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *)obj;
1151 
1152  while (plugin->in_types) {
1153  xmms_object_unref (plugin->in_types->data);
1154 
1155  plugin->in_types = g_list_delete_link (plugin->in_types,
1156  plugin->in_types);
1157  }
1158 
1160 }
1161 
1162 xmms_plugin_t *
1164 {
1165  xmms_xform_plugin_t *res;
1166 
1167  res = xmms_object_new (xmms_xform_plugin_t, xmms_xform_plugin_destroy);
1168 
1169  return (xmms_plugin_t *)res;
1170 }
1171 
1172 void
1174  xmms_xform_methods_t *methods)
1175 {
1176 
1177  g_return_if_fail (plugin);
1178  g_return_if_fail (plugin->plugin.type == XMMS_PLUGIN_TYPE_XFORM);
1179 
1180  XMMS_DBG ("Registering xform '%s'",
1182 
1183  memcpy (&plugin->methods, methods, sizeof (xmms_xform_methods_t));
1184 }
1185 
1186 gboolean
1188 {
1189  xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *) _plugin;
1190 
1191  g_return_val_if_fail (plugin, FALSE);
1192  g_return_val_if_fail (plugin->plugin.type == XMMS_PLUGIN_TYPE_XFORM, FALSE);
1193 
1194  /* more checks */
1195 
1196  return TRUE;
1197 }
1198 
1199 void
1201 {
1202  xmms_stream_type_t *t;
1203  va_list ap;
1204  gchar *config_key, config_value[32];
1205  gint priority;
1206 
1207  va_start (ap, plugin);
1208  t = xmms_stream_type_parse (ap);
1209  va_end (ap);
1210 
1211  config_key = g_strconcat ("priority.",
1213  NULL);
1215  g_snprintf (config_value, sizeof (config_value), "%d", priority);
1216  xmms_xform_plugin_config_property_register (plugin, config_key,
1217  config_value, NULL, NULL);
1218  g_free (config_key);
1219 
1220  plugin->in_types = g_list_prepend (plugin->in_types, t);
1221 }
1222 
1223 static gboolean
1224 xmms_xform_plugin_supports (xmms_xform_plugin_t *plugin, xmms_stream_type_t *st,
1225  gint *priority)
1226 {
1227  GList *t;
1228 
1229  for (t = plugin->in_types; t; t = g_list_next (t)) {
1230  if (xmms_stream_type_match (t->data, st)) {
1231  if (priority) {
1232  gchar *config_key;
1233  xmms_config_property_t *conf_priority;
1234 
1235  config_key = g_strconcat ("priority.",
1237  NULL);
1238  conf_priority = xmms_plugin_config_lookup ((xmms_plugin_t *)plugin,
1239  config_key);
1240  g_free (config_key);
1241 
1242  if (conf_priority) {
1243  *priority = xmms_config_property_get_int (conf_priority);
1244  } else {
1246  }
1247  }
1248  return TRUE;
1249  }
1250  }
1251  return FALSE;
1252 }
1253 
1254 typedef struct match_state_St {
1255  xmms_xform_plugin_t *match;
1256  xmms_stream_type_t *out_type;
1257  gint priority;
1258 } match_state_t;
1259 
1260 static gboolean
1261 xmms_xform_match (xmms_plugin_t *_plugin, gpointer user_data)
1262 {
1263  xmms_xform_plugin_t *plugin = (xmms_xform_plugin_t *)_plugin;
1264  match_state_t *state = (match_state_t *)user_data;
1265  gint priority;
1266 
1267  g_assert (_plugin->type == XMMS_PLUGIN_TYPE_XFORM);
1268 
1269  if (!plugin->in_types) {
1270  XMMS_DBG ("Skipping plugin '%s'", xmms_plugin_shortname_get (_plugin));
1271  return TRUE;
1272  }
1273 
1274  XMMS_DBG ("Trying plugin '%s'", xmms_plugin_shortname_get (_plugin));
1275  if (xmms_xform_plugin_supports (plugin, state->out_type, &priority)) {
1276  XMMS_DBG ("Plugin '%s' matched (priority %d)",
1277  xmms_plugin_shortname_get (_plugin), priority);
1278  if (priority > state->priority) {
1279  if (state->match) {
1280  XMMS_DBG ("Using plugin '%s' (priority %d) instead of '%s' (priority %d)",
1281  xmms_plugin_shortname_get (_plugin), priority,
1282  xmms_plugin_shortname_get ((xmms_plugin_t *)state->match),
1283  state->priority);
1284  }
1285 
1286  state->match = plugin;
1287  state->priority = priority;
1288  }
1289  }
1290 
1291  return TRUE;
1292 }
1293 
1294 xmms_xform_t *
1296  GList *goal_hints)
1297 {
1298  match_state_t state;
1299  xmms_xform_t *xform = NULL;
1300 
1301  state.out_type = prev->out_type;
1302  state.match = NULL;
1303  state.priority = -1;
1304 
1305  xmms_plugin_foreach (XMMS_PLUGIN_TYPE_XFORM, xmms_xform_match, &state);
1306 
1307  if (state.match) {
1308  xform = xmms_xform_new (state.match, prev, entry, goal_hints);
1309  } else {
1310  XMMS_DBG ("Found no matching plugin...");
1311  }
1312 
1313  return xform;
1314 }
1315 
1316 gboolean
1318 {
1319  gboolean ret = TRUE;
1320 
1321  if (xform->prev) {
1322  ret = xform->prev->eos;
1323  }
1324 
1325  return ret;
1326 }
1327 
1328 const xmms_stream_type_t *
1330 {
1331  return xform->out_type;
1332 }
1333 
1334 const GList *
1336 {
1337  return xform->goal_hints;
1338 }
1339 
1340 
1341 static gboolean
1342 has_goalformat (xmms_xform_t *xform, GList *goal_formats)
1343 {
1344  const xmms_stream_type_t *current;
1345  gboolean ret = FALSE;
1346  GList *n;
1347 
1348  current = xmms_xform_get_out_stream_type (xform);
1349 
1350  for (n = goal_formats; n; n = g_list_next (n)) {
1351  xmms_stream_type_t *goal_type = n->data;
1352  if (xmms_stream_type_match (goal_type, current)) {
1353  ret = TRUE;
1354  break;
1355  }
1356 
1357  }
1358 
1359  if (!ret) {
1360  XMMS_DBG ("Not in one of %d goal-types", g_list_length (goal_formats));
1361  }
1362 
1363  return ret;
1364 }
1365 
1366 static void
1367 outdata_type_metadata_collect (xmms_xform_t *xform)
1368 {
1369  gint val;
1370  const char *mime;
1371  xmms_stream_type_t *type;
1372 
1373  type = xform->out_type;
1375  if (strcmp (mime, "audio/pcm") != 0) {
1376  return;
1377  }
1378 
1380  if (val != -1) {
1381  const gchar *name = xmms_sample_name_get ((xmms_sample_format_t) val);
1384  name);
1385  }
1386 
1388  if (val != -1) {
1391  val);
1392  }
1393 
1395  if (val != -1) {
1398  val);
1399  }
1400 }
1401 
1402 static xmms_xform_t *
1403 chain_setup (xmms_medialib_entry_t entry, const gchar *url, GList *goal_formats)
1404 {
1405  xmms_xform_t *xform, *last;
1406  gchar *durl, *args;
1407 
1408  if (!entry) {
1409  entry = 1; /* FIXME: this is soooo ugly, don't do this */
1410  }
1411 
1412  xform = xmms_xform_new (NULL, NULL, 0, goal_formats);
1413 
1414  durl = g_strdup (url);
1415 
1416  args = strchr (durl, '?');
1417  if (args) {
1418  gchar **params;
1419  gint i;
1420  *args = 0;
1421  args++;
1422  xmms_medialib_decode_url (args);
1423 
1424  params = g_strsplit (args, "&", 0);
1425 
1426  for (i = 0; params && params[i]; i++) {
1427  gchar *v;
1428  v = strchr (params[i], '=');
1429  if (v) {
1430  *v = 0;
1431  v++;
1432  xmms_xform_metadata_set_str (xform, params[i], v);
1433  } else {
1434  xmms_xform_metadata_set_int (xform, params[i], 1);
1435  }
1436  }
1437  g_strfreev (params);
1438  }
1439  xmms_medialib_decode_url (durl);
1440 
1442  "application/x-url", XMMS_STREAM_TYPE_URL,
1443  durl, XMMS_STREAM_TYPE_END);
1444 
1445  g_free (durl);
1446 
1447  last = xform;
1448 
1449  do {
1450  xform = xmms_xform_find (last, entry, goal_formats);
1451  if (!xform) {
1452  xmms_log_error ("Couldn't set up chain for '%s' (%d)",
1453  url, entry);
1454  xmms_object_unref (last);
1455 
1456  return NULL;
1457  }
1458  xmms_object_unref (last);
1459  last = xform;
1460  } while (!has_goalformat (xform, goal_formats));
1461 
1462  outdata_type_metadata_collect (last);
1463 
1464  return last;
1465 }
1466 
1467 static void
1468 chain_finalize (xmms_xform_t *xform, xmms_medialib_entry_t entry,
1469  const gchar *url, gboolean rehashing)
1470 {
1471  GString *namestr;
1472 
1473  namestr = g_string_new ("");
1474  xmms_xform_metadata_collect (xform, namestr, rehashing);
1475  xmms_log_info ("Successfully setup chain for '%s' (%d) containing %s",
1476  url, entry, namestr->str);
1477 
1478  g_string_free (namestr, TRUE);
1479 }
1480 
1481 static gchar *
1482 get_url_for_entry (xmms_medialib_entry_t entry)
1483 {
1484  xmms_medialib_session_t *session;
1485  gchar *url = NULL;
1486 
1487  session = xmms_medialib_begin ();
1488  url = xmms_medialib_entry_property_get_str (session, entry,
1490  xmms_medialib_end (session);
1491 
1492  if (!url) {
1493  xmms_log_error ("Couldn't get url for entry (%d)", entry);
1494  }
1495 
1496  return url;
1497 }
1498 
1499 xmms_xform_t *
1500 xmms_xform_chain_setup (xmms_medialib_entry_t entry, GList *goal_formats,
1501  gboolean rehash)
1502 {
1503  gchar *url;
1504  xmms_xform_t *xform;
1505 
1506  if (!(url = get_url_for_entry (entry))) {
1507  return NULL;
1508  }
1509 
1510  xform = xmms_xform_chain_setup_url (entry, url, goal_formats, rehash);
1511  g_free (url);
1512 
1513  return xform;
1514 }
1515 
1516 xmms_xform_t *
1518  GList *goal_formats, gboolean rehash)
1519 {
1520  xmms_xform_t *last;
1521  xmms_plugin_t *plugin;
1522  xmms_xform_plugin_t *xform_plugin;
1523  gboolean add_segment = FALSE;
1524 
1525  last = chain_setup (entry, url, goal_formats);
1526  if (!last) {
1527  return NULL;
1528  }
1529 
1530  /* first check that segment plugin is available in the system */
1531  plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, "segment");
1532  xform_plugin = (xmms_xform_plugin_t *) plugin;
1533 
1534  /* if segment plugin input is the same as current output, include it
1535  * for collecting additional duration metadata on audio entries */
1536  if (xform_plugin) {
1537  add_segment = xmms_xform_plugin_supports (xform_plugin,
1538  last->out_type,
1539  NULL);
1540  xmms_object_unref (plugin);
1541  }
1542 
1543  /* add segment plugin to the chain if it can be added */
1544  if (add_segment) {
1545  last = xmms_xform_new_effect (last, entry, goal_formats, "segment");
1546  if (!last) {
1547  return NULL;
1548  }
1549  }
1550 
1551  /* if not rehashing, also initialize all the effect plugins */
1552  if (!rehash) {
1553  last = add_effects (last, entry, goal_formats);
1554  if (!last) {
1555  return NULL;
1556  }
1557  }
1558 
1559  chain_finalize (last, entry, url, rehash);
1560  return last;
1561 }
1562 
1565  const gchar *name,
1566  const gchar *default_value,
1568  gpointer userdata)
1569 {
1570  xmms_plugin_t *plugin = (xmms_plugin_t *) xform_plugin;
1571 
1572  return xmms_plugin_config_property_register (plugin, name,
1573  default_value,
1574  cb, userdata);
1575 }
1576 
1578 xmms_xform_config_lookup (xmms_xform_t *xform, const gchar *path)
1579 {
1580  g_return_val_if_fail (xform->plugin, NULL);
1581 
1582  return xmms_plugin_config_lookup ((xmms_plugin_t *) xform->plugin, path);
1583 }
1584 
1585 static xmms_xform_t *
1586 add_effects (xmms_xform_t *last, xmms_medialib_entry_t entry,
1587  GList *goal_formats)
1588 {
1589  gint effect_no;
1590 
1591  for (effect_no = 0; TRUE; effect_no++) {
1593  gchar key[64];
1594  const gchar *name;
1595 
1596  g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
1597 
1598  cfg = xmms_config_lookup (key);
1599  if (!cfg) {
1600  break;
1601  }
1602 
1603  name = xmms_config_property_get_string (cfg);
1604 
1605  if (!name[0]) {
1606  continue;
1607  }
1608 
1609  last = xmms_xform_new_effect (last, entry, goal_formats, name);
1610  }
1611 
1612  return last;
1613 }
1614 
1615 static xmms_xform_t *
1616 xmms_xform_new_effect (xmms_xform_t *last, xmms_medialib_entry_t entry,
1617  GList *goal_formats, const gchar *name)
1618 {
1619  xmms_plugin_t *plugin;
1620  xmms_xform_plugin_t *xform_plugin;
1621  xmms_xform_t *xform;
1622 
1623  plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
1624  if (!plugin) {
1625  xmms_log_error ("Couldn't find any effect named '%s'", name);
1626  return last;
1627  }
1628 
1629  xform_plugin = (xmms_xform_plugin_t *) plugin;
1630  if (!xmms_xform_plugin_supports (xform_plugin, last->out_type, NULL)) {
1631  xmms_log_info ("Effect '%s' doesn't support format, skipping",
1632  xmms_plugin_shortname_get (plugin));
1633  xmms_object_unref (plugin);
1634  return last;
1635  }
1636 
1637  xform = xmms_xform_new (xform_plugin, last, entry, goal_formats);
1638 
1639  if (xform) {
1640  xmms_object_unref (last);
1641  last = xform;
1642  } else {
1643  xmms_log_info ("Effect '%s' failed to initialize, skipping",
1644  xmms_plugin_shortname_get (plugin));
1645  }
1647  "enabled", "0",
1648  NULL, NULL);
1649  xmms_object_unref (plugin);
1650  return last;
1651 }
1652 
1653 static void
1654 update_effect_properties (xmms_object_t *object, xmmsv_t *data,
1655  gpointer userdata)
1656 {
1657  gint effect_no = GPOINTER_TO_INT (userdata);
1658  const gchar *name;
1659 
1661  xmms_xform_plugin_t *xform_plugin;
1662  xmms_plugin_t *plugin;
1663  gchar key[64];
1664 
1666 
1667  if (name[0]) {
1668  plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
1669  if (!plugin) {
1670  xmms_log_error ("Couldn't find any effect named '%s'", name);
1671  } else {
1672  xform_plugin = (xmms_xform_plugin_t *) plugin;
1673  xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
1674  "1", NULL, NULL);
1675  xmms_object_unref (plugin);
1676  }
1677 
1678  /* setup new effect.order.n */
1679  g_snprintf (key, sizeof (key), "effect.order.%i", effect_no + 1);
1680 
1681  cfg = xmms_config_lookup (key);
1682  if (!cfg) {
1683  xmms_config_property_register (key, "", update_effect_properties,
1684  GINT_TO_POINTER (effect_no + 1));
1685  }
1686  }
1687 }
1688 
1689 static void
1690 effect_callbacks_init (void)
1691 {
1692  gint effect_no;
1693 
1695  xmms_xform_plugin_t *xform_plugin;
1696  xmms_plugin_t *plugin;
1697  gchar key[64];
1698  const gchar *name;
1699 
1700  for (effect_no = 0; ; effect_no++) {
1701  g_snprintf (key, sizeof (key), "effect.order.%i", effect_no);
1702 
1703  cfg = xmms_config_lookup (key);
1704  if (!cfg) {
1705  break;
1706  }
1707  xmms_config_property_callback_set (cfg, update_effect_properties,
1708  GINT_TO_POINTER (effect_no));
1709 
1710  name = xmms_config_property_get_string (cfg);
1711  if (!name[0]) {
1712  continue;
1713  }
1714 
1715  plugin = xmms_plugin_find (XMMS_PLUGIN_TYPE_XFORM, name);
1716  if (!plugin) {
1717  xmms_log_error ("Couldn't find any effect named '%s'", name);
1718  continue;
1719  }
1720 
1721  xform_plugin = (xmms_xform_plugin_t *) plugin;
1722  xmms_xform_plugin_config_property_register (xform_plugin, "enabled",
1723  "1", NULL, NULL);
1724 
1725  xmms_object_unref (plugin);
1726  }
1727 
1728  /* the name stored in the last present property was not "" or there was no
1729  last present property */
1730  if ((!effect_no) || name[0]) {
1731  xmms_config_property_register (key, "", update_effect_properties,
1732  GINT_TO_POINTER (effect_no));
1733  }
1734 }
1735 
struct xmmsv_St xmmsv_t
Definition: xmmsv.h:51
#define XMMS_CMD_FUNC(cmdid)
Definition: xmms_object.h:181
gchar * xmms_medialib_url_encode(const gchar *path)
Definition: medialib.c:1565
xmmsv_t * xmmsv_new_dict(void)
Allocates a new dict xmmsv_t.
Definition: value.c:266
gboolean xmms_xform_metadata_has_val(xmms_xform_t *xform, const gchar *key)
Definition: xform.c:563
gboolean xmms_xform_plugin_verify(xmms_plugin_t *_plugin)
Definition: xform.c:1187
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
Definition: xmms_medialib.h:86
void xmms_xform_auxdata_set_int(xmms_xform_t *xform, const char *key, int intval)
Definition: xform.c:760
#define XMMS_OBJECT(p)
Definition: xmms_object.h:84
struct xmms_xform_plugin_St xmms_xform_plugin_t
Xform plugin.
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:171
#define XMMS_XFORM_BROWSE_FLAG_DIR
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed...
Definition: value.c:301
int xmmsv_dict_set(xmmsv_t *dictv, const char *key, xmmsv_t *val)
Insert an element under the given key in the dict xmmsv_t.
Definition: value.c:1744
#define xmms_object_unref(obj)
Definition: xmms_object.h:193
struct xmms_xform_hotspot_St xmms_xform_hotspot_t
gchar * xmms_xform_read_line(xmms_xform_t *xform, gchar *line, xmms_error_t *err)
Read one line from previous xform.
Definition: xform.c:1073
void xmms_xform_browse_add_symlink(xmms_xform_t *xform, const gchar *basename, const gchar *url)
Definition: xform.c:158
xmms_config_property_t * xmms_plugin_config_property_register(xmms_plugin_t *plugin, const gchar *name, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Definition: plugin.c:104
xmms_xform_t * xmms_xform_chain_setup(xmms_medialib_entry_t entry, GList *goal_formats, gboolean rehash)
Definition: xform.c:1500
gint xmms_medialib_entry_property_get_int(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property)
Retrieve a property as a int from a entry.
Definition: medialib.c:588
xmms_sample_format_t
Definition: xmms_sample.h:25
struct xmms_stream_type_St xmms_stream_type_t
xmms_xform_object_t * xmms_xform_object_init(void)
Definition: xform.c:335
void xmms_xform_outdata_type_set(xmms_xform_t *xform, xmms_stream_type_t *type)
Definition: xform.c:450
void xmms_xform_plugin_indata_add(xmms_xform_plugin_t *plugin,...)
Add a valid input type to the plugin.
Definition: xform.c:1200
void xmms_object_cmd_add(xmms_object_t *object, guint cmdid, const xmms_object_cmd_desc_t *desc)
Add a command that could be called from the client API to a object.
Definition: object.c:321
xmms_config_property_t * xmms_config_lookup(const gchar *path)
Look up a config key from the global config.
Definition: config.c:174
void xmms_xform_browse_add_entry_property(xmms_xform_t *xform, const gchar *key, xmmsv_t *val)
Definition: xform.c:165
#define XMMS_XFORM_MAX_LINE_SIZE
xmmsv_t * xmmsv_new_none(void)
Allocates a new empty xmmsv_t.
Definition: value.c:127
void xmms_medialib_entry_cleanup(xmms_medialib_session_t *session, xmms_medialib_entry_t entry)
Definition: medialib.c:846
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
Definition: value.c:178
struct xmms_xform_St xmms_xform_t
xmms_plugin_t * xmms_xform_plugin_new(void)
Definition: xform.c:1163
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition: value.c:815
void xmms_xform_browse_add_symlink_args(xmms_xform_t *xform, const gchar *basename, const gchar *url, gint nargs, gchar **args)
Definition: xform.c:129
gint xmms_xform_outtype_get_int(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition: xform.c:509
XMMS_CMD_DEFINE(browse, xmms_xform_client_browse, xmms_xform_object_t *, LIST, STRING, NONE)
gboolean xmms_medialib_entry_property_set_int_source(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property, gint value, guint32 source)
Definition: medialib.c:627
gboolean xmms_medialib_entry_property_set_str(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property, const gchar *value)
Set a entry property to a new value, overwriting the old value.
Definition: medialib.c:666
guint32 xmms_medialib_source_to_id(xmms_medialib_session_t *session, const gchar *source)
Definition: medialib.c:273
const gchar * xmms_plugin_shortname_get(const xmms_plugin_t *plugin)
Definition: plugin.c:158
xmms_xform_t * xmms_xform_chain_setup_url(xmms_medialib_entry_t entry, const gchar *url, GList *goal_formats, gboolean rehash)
Definition: xform.c:1517
GList * xmms_xform_browse_method(xmms_xform_t *xform, const gchar *url, xmms_error_t *error)
Definition: xform.c:259
#define READ_CHUNK
Definition: xform.c:84
void xmms_xform_browse_add_entry_property_int(xmms_xform_t *xform, const gchar *key, gint value)
Definition: xform.c:119
void xmms_xform_auxdata_barrier(xmms_xform_t *xform)
Definition: xform.c:753
gint xmms_config_property_get_int(const xmms_config_property_t *prop)
Return the value of a config property as an int.
Definition: config.c:258
int xmmsv_dict_get(xmmsv_t *dictv, const char *key, xmmsv_t **val)
Get the element corresponding to the given key in the dict xmmsv_t (if it exists).
Definition: value.c:1709
gboolean xmms_stream_type_match(const xmms_stream_type_t *in_type, const xmms_stream_type_t *out_type)
Definition: streamtype.c:210
gpointer xmms_xform_private_data_get(xmms_xform_t *xform)
Get private data for this xform.
Definition: xform.c:429
void xmms_xform_metadata_set_int(xmms_xform_t *xform, const char *key, int val)
Definition: xform.c:516
#define XMMS_MEDIALIB_ENTRY_PROPERTY_TIMESPLAYED
Definition: xmms_medialib.h:61
gboolean xmms_xform_auxdata_get_bin(xmms_xform_t *xform, const gchar *key, const guchar **data, gsize *datalen)
Definition: xform.c:855
#define xmms_log_error(fmt,...)
Definition: xmms_log.h:35
#define XMMS_MEDIALIB_ENTRY_PROPERTY_CHANNELS
Definition: xmms_medialib.h:41
void xmms_config_property_callback_set(xmms_config_property_t *prop, xmms_object_handler_t cb, gpointer userdata)
Set a callback function for a config property.
Definition: config.c:290
#define XMMS_PLUGIN_SHORTNAME_MAX_LEN
Definition: xmms_plugin.h:27
const char * xmms_xform_indata_get_str(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition: xform.c:477
enum xmms_xform_seek_mode_E xmms_xform_seek_mode_t
Seek direction argument.
void xmms_xform_metadata_set_str(xmms_xform_t *xform, const char *key, const char *val)
Definition: xform.c:525
const xmms_stream_type_t * xmms_xform_get_out_stream_type(xmms_xform_t *xform)
Definition: xform.c:1329
xmms_xform_t * xmms_xform_find(xmms_xform_t *prev, xmms_medialib_entry_t entry, GList *goal_hints)
Definition: xform.c:1295
Methods provided by an xform plugin.
const gchar * xmms_config_property_get_string(const xmms_config_property_t *prop)
Return the value of a config property as a string.
Definition: config.c:246
gint xmms_natcmp(const gchar *str1, const gchar *str2)
Definition: utils.c:150
GList * xmms_xform_browse(const gchar *url, xmms_error_t *error)
Definition: xform.c:279
void xmms_xform_auxdata_set_str(xmms_xform_t *xform, const gchar *key, const gchar *strval)
Definition: xform.c:767
void xmms_xform_plugin_methods_set(xmms_xform_plugin_t *plugin, xmms_xform_methods_t *methods)
Should be called once from the plugin's setupfunc.
Definition: xform.c:1173
const gchar * xmms_xform_get_url(xmms_xform_t *xform)
Definition: xform.c:1133
gint64 xmms_xform_seek(xmms_xform_t *xform, gint64 offset, xmms_xform_seek_mode_t whence, xmms_error_t *err)
Change offset in stream.
Definition: xform.c:1125
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
Definition: value.c:384
void xmms_plugin_foreach(xmms_plugin_type_t type, xmms_plugin_foreach_func_t func, gpointer user_data)
Definition: plugin.c:406
struct xmms_xform_object_St xmms_xform_object_t
Definition: xmms_xform.h:25
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
Definition: value.c:159
xmms_medialib_entry_t xmms_xform_entry_get(xmms_xform_t *xform)
Get the medialib entry played by this xform.
Definition: xform.c:423
void xmms_ipc_object_unregister(xmms_ipc_objects_t objectid)
Remove a object from the IPC core.
Definition: ipc.c:769
#define XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED
Definition: xmms_medialib.h:56
xmms_config_property_t * xmms_xform_config_lookup(xmms_xform_t *xform, const gchar *path)
Definition: xform.c:1578
gboolean xmms_xform_auxdata_get_int(xmms_xform_t *xform, const gchar *key, gint32 *val)
Definition: xform.c:826
struct xmms_medialib_session_St xmms_medialib_session_t
Definition: xmms_medialib.h:87
gint64 xmms_xform_this_seek(xmms_xform_t *xform, gint64 offset, xmms_xform_seek_mode_t whence, xmms_error_t *err)
Definition: xform.c:1026
gboolean xmms_xform_auxdata_get_str(xmms_xform_t *xform, const gchar *key, const gchar **val)
Definition: xform.c:840
#define XMMS_MEDIALIB_ENTRY_PROPERTY_CHAIN
Definition: xmms_medialib.h:60
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
#define XMMS_STREAM_TYPE_PRIORITY_DEFAULT
void xmms_xform_outdata_type_copy(xmms_xform_t *xform)
Definition: xform.c:457
gboolean xmms_xform_metadata_get_int(xmms_xform_t *xform, const char *key, gint32 *val)
Definition: xform.c:569
const char * xmms_xform_indata_find_str(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition: xform.c:464
xmms_config_property_t * xmms_xform_plugin_config_property_register(xmms_xform_plugin_t *xform_plugin, const gchar *name, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Definition: xform.c:1564
void xmms_medialib_entry_send_update(xmms_medialib_entry_t entry)
Trigger a update signal to the client.
Definition: medialib.c:719
void xmms_plugin_destroy(xmms_plugin_t *plugin)
Definition: plugin.c:466
xmms_xform_t * xmms_xform_new(xmms_xform_plugin_t *plugin, xmms_xform_t *prev, xmms_medialib_entry_t entry, GList *goal_hints)
Definition: xform.c:380
xmmsv_t * xmmsv_new_bin(unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
Definition: value.c:223
gint xmms_xform_read(xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
Read data from previous xform.
Definition: xform.c:1118
#define xmms_object_ref(obj)
Definition: xmms_object.h:187
#define MIN(a, b)
Definition: xmmsc_util.h:35
void xmms_xform_outdata_type_add(xmms_xform_t *xform,...)
Definition: xform.c:441
int xmmsv_get_bin(const xmmsv_t *val, const unsigned char **r, unsigned int *rlen)
Retrieves binary data from the value.
Definition: value.c:896
const char * xmms_xform_outtype_get_str(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition: xform.c:503
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
#define xmms_medialib_begin_write()
#define xmms_medialib_begin()
G_BEGIN_DECLS enum xmms_stream_type_key_E xmms_stream_type_key_t
gint xmms_xform_peek(xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
Preview data from previous xform.
Definition: xform.c:1065
gboolean xmms_medialib_entry_property_set_str_source(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property, const gchar *value, guint32 source)
Definition: medialib.c:677
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition: value.c:855
#define XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLE_FMT
Definition: xmms_medialib.h:42
gboolean xmms_medialib_decode_url(char *url)
Definition: medialib.c:1517
#define xmms_object_new(objtype, destroyfunc)
Definition: xmms_object.h:199
gint xmms_xform_indata_get_int(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition: xform.c:483
#define xmms_medialib_entry_status_set(session, e, st)
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
#define XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE
Definition: xmms_medialib.h:43
xmms_config_property_t * xmms_config_property_register(const gchar *path, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Register a new config property.
Definition: config.c:337
xmms_config_property_t * xmms_plugin_config_lookup(xmms_plugin_t *plugin, const gchar *key)
Definition: plugin.c:76
struct xmms_config_property_St xmms_config_property_t
Definition: xmms_config.h:26
void xmms_xform_auxdata_set_bin(xmms_xform_t *xform, const gchar *key, gpointer data, gssize len)
Definition: xform.c:784
xmms_stream_type_t * xmms_xform_outtype_get(xmms_xform_t *xform)
Definition: xform.c:489
xmms_plugin_t * xmms_plugin_find(xmms_plugin_type_t type, const gchar *name)
Definition: plugin.c:445
gboolean xmms_medialib_entry_property_set_int(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property, gint value)
Set a entry property to a new value, overwriting the old value.
Definition: medialib.c:616
gint xmms_xform_this_read(xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
Definition: xform.c:948
const char * xmms_stream_type_get_str(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:148
void xmms_ipc_object_register(xmms_ipc_objects_t objectid, xmms_object_t *object)
Register a object to the IPC core.
Definition: ipc.c:758
void(* xmms_object_handler_t)(xmms_object_t *object, xmmsv_t *data, gpointer userdata)
Definition: xmms_object.h:67
struct match_state_St match_state_t
const char * xmms_xform_shortname(xmms_xform_t *xform)
Definition: xform.c:870
#define XMMS_MEDIALIB_ENTRY_PROPERTY_URL
Definition: xmms_medialib.h:29
void xmms_xform_browse_add_entry(xmms_xform_t *xform, const gchar *filename, guint32 flags)
Definition: xform.c:177
void xmms_xform_private_data_set(xmms_xform_t *xform, gpointer data)
Set private data for this xform.
Definition: xform.c:435
gchar * xmms_medialib_entry_property_get_str(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property)
Retrieve a property from an entry.
Definition: medialib.c:561
xmms_stream_type_t * xmms_xform_intype_get(xmms_xform_t *xform)
Definition: xform.c:495
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)
Definition: streamtype.c:71
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition: medialib.c:470
void xmms_xform_browse_add_entry_property_str(xmms_xform_t *xform, const gchar *key, const gchar *value)
Definition: xform.c:108
gboolean xmms_xform_metadata_get_str(xmms_xform_t *xform, const char *key, const gchar **val)
Definition: xform.c:585
gboolean xmms_xform_auxdata_has_val(xmms_xform_t *xform, const gchar *key)
Definition: xform.c:820
const GList * xmms_xform_goal_hints_get(xmms_xform_t *xform)
Definition: xform.c:1335
xmms_plugin_type_t type
Definition: xmms_plugin.h:33
gboolean xmms_xform_iseos(xmms_xform_t *xform)
Definition: xform.c:1317