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