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
25#include "xmmspriv/xmms_xform.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
34struct xmms_xform_object_St {
35 xmms_object_t obj;
36};
37
38struct 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
79typedef 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);
90const char *xmms_xform_shortname (xmms_xform_t *xform);
91static xmms_xform_t *add_effects (xmms_xform_t *last,
93 GList *goal_formats);
94static xmms_xform_t *xmms_xform_new_effect (xmms_xform_t* last,
96 GList *goal_formats,
97 const gchar *name);
98static void xmms_xform_destroy (xmms_object_t *object);
99static void effect_callbacks_init (void);
100
101static GList *xmms_xform_client_browse (xmms_xform_object_t *obj, const gchar *url, xmms_error_t *error);
102
103#include "xform_ipc.c"
104
105void
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
116void
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
126void
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
155void
156xmms_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
162void
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
174void
175xmms_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);
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
217static gint
218xmms_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
256GList *
257xmms_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
276GList *
277xmms_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
317static GList *
318xmms_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
324static void
325xmms_xform_object_destroy (xmms_object_t *obj)
326{
327 xmms_xform_unregister_ipc_commands ();
328}
329
332{
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
344static void
345xmms_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
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
423gpointer
425{
426 return xform->priv;
427}
428
429void
431{
432 xform->priv = data;
433}
434
435void
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
444void
446{
447 xmms_object_ref (type);
448 xform->out_type = type;
449}
450
451void
453{
454 xmms_object_ref (xform->prev->out_type);
455 xform->out_type = xform->prev->out_type;
456}
457
458const 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
471const char *
473{
474 return xmms_stream_type_get_str (xform->prev->out_type, key);
475}
476
477gint
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
497const char *
499{
500 return xmms_stream_type_get_str (xform->out_type, key);
501}
502
503gint
505{
506 return xmms_stream_type_get_int (xform->out_type, key);
507}
508
509
510void
511xmms_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
519void
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
542static const xmmsv_t *
543xmms_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
557gboolean
559{
560 return !!xmms_xform_metadata_get_val (xform, key);
561}
562
563gboolean
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
579gboolean
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
595typedef struct {
598 guint32 source;
599} metadata_festate_t;
600
601static void
602add_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
629static void
630xmms_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
645static void
646xmms_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
667static void
668xmms_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);
718}
719
720static void
721xmms_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);
732}
733
734static void
735xmms_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
747void
749{
750 xmmsv_t *val = xmmsv_new_none ();
751 xmms_xform_auxdata_set_val (xform, NULL, val);
752}
753
754void
755xmms_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
761void
762xmms_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
778void
779xmms_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
788static const xmmsv_t *
789xmms_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
814gboolean
815xmms_xform_auxdata_has_val (xmms_xform_t *xform, const gchar *key)
816{
817 return !!xmms_xform_auxdata_get_val (xform, key);
818}
819
820gboolean
821xmms_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
834gboolean
835xmms_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
849gboolean
850xmms_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
864const char *
866{
867 return (xform->plugin)
868 ? xmms_plugin_shortname_get ((xmms_plugin_t *) xform->plugin)
869 : "unknown";
870}
871
872static gint
873xmms_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
911static void
912xmms_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
920static gint
921xmms_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
942gint
943xmms_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
1020gint64
1021xmms_xform_this_seek (xmms_xform_t *xform, gint64 offset,
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
1059gint
1060xmms_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
1067gchar *
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
1112gint
1113xmms_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
1119gint64
1120xmms_xform_seek (xmms_xform_t *xform, gint64 offset,
1122{
1123 g_return_val_if_fail (xform->prev, -1);
1124 return xmms_xform_this_seek (xform->prev, offset, whence, err);
1125}
1126
1127const 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
1143typedef struct match_state_St {
1144 xmms_xform_plugin_t *match;
1145 xmms_stream_type_t *out_type;
1146 gint priority;
1148
1149static gboolean
1150xmms_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
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
1204gboolean
1206{
1207 gboolean ret = TRUE;
1208
1209 if (xform->prev) {
1210 ret = xform->prev->eos;
1211 }
1212
1213 return ret;
1214}
1215
1216const xmms_stream_type_t *
1218{
1219 return xform->out_type;
1220}
1221
1222const GList *
1224{
1225 return xform->goal_hints;
1226}
1227
1228
1229static gboolean
1230has_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
1254static void
1255outdata_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
1290static xmms_xform_t *
1291chain_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++;
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 }
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
1355static void
1356chain_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
1369static gchar *
1370get_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
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
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
1453xmms_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
1460static xmms_xform_t *
1461add_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
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
1490static xmms_xform_t *
1491xmms_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
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
1529static void
1530update_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]) {
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
1565static void
1566effect_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
1587 if (!name[0]) {
1588 continue;
1589 }
1590
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
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
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
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
xmms_config_property_t * xmms_config_lookup(const gchar *path)
Look up a config key from the global config.
Definition config.c:171
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
xmmsv_t * xmmsv_new_dict(void)
Allocates a new dict xmmsv_t.
Definition value.c:268
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
guint32 xmms_medialib_source_to_id(xmms_medialib_session_t *session, const gchar *source)
Definition medialib.c:261
void xmms_medialib_entry_cleanup(xmms_medialib_session_t *session, xmms_medialib_entry_t entry)
Definition medialib.c:802
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
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
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
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
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
void xmms_medialib_entry_send_update(xmms_medialib_entry_t entry)
Trigger a update signal to the client.
Definition medialib.c:674
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
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition medialib.c:425
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
xmmsv_t * xmmsv_new_none(void)
Allocates a new empty xmmsv_t.
Definition value.c:129
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
Definition value.c:180
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition value.c:863
struct xmmsv_St xmmsv_t
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition value.c:823
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
Definition value.c:392
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
Definition value.c:161
xmmsv_t * xmmsv_new_bin(const unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
Definition value.c:225
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
@ XMMSV_TYPE_DICT
@ XMMSV_TYPE_BIN
@ XMMSV_TYPE_INT32
@ XMMSV_TYPE_STRING
void xmms_xform_private_data_set(xmms_xform_t *xform, gpointer data)
Set private data for this xform.
Definition xform.c:430
struct xmms_xform_plugin_St xmms_xform_plugin_t
Xform plugin.
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
gpointer xmms_xform_private_data_get(xmms_xform_t *xform)
Get private data for this xform.
Definition xform.c:424
gboolean xmms_xform_metadata_has_val(xmms_xform_t *xform, const gchar *key)
Definition xform.c:558
struct xmms_xform_St xmms_xform_t
void xmms_xform_browse_add_symlink(xmms_xform_t *xform, const gchar *basename, const gchar *url)
Definition xform.c:156
void xmms_xform_browse_add_entry_property_int(xmms_xform_t *xform, const gchar *key, gint value)
Definition xform.c:117
gboolean xmms_xform_auxdata_get_bin(xmms_xform_t *xform, const gchar *key, const guchar **data, gsize *datalen)
Definition xform.c:850
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)
xmms_config_property_t * xmms_xform_config_lookup(xmms_xform_t *xform, const gchar *path)
Definition xform.c:1453
void xmms_xform_outdata_type_add(xmms_xform_t *xform,...)
Definition xform.c:436
xmms_medialib_entry_t xmms_xform_entry_get(xmms_xform_t *xform)
Get the medialib entry played by this xform.
Definition xform.c:418
void xmms_xform_browse_add_entry_property(xmms_xform_t *xform, const gchar *key, xmmsv_t *val)
Definition xform.c:163
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
void xmms_xform_browse_add_entry(xmms_xform_t *xform, const gchar *filename, guint32 flags)
Definition xform.c:175
void xmms_xform_auxdata_set_str(xmms_xform_t *xform, const gchar *key, const gchar *strval)
Definition xform.c:762
void xmms_xform_auxdata_barrier(xmms_xform_t *xform)
Definition xform.c:748
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
const gchar * xmms_xform_get_url(xmms_xform_t *xform)
Definition xform.c:1128
gboolean xmms_xform_auxdata_get_str(xmms_xform_t *xform, const gchar *key, const gchar **val)
Definition xform.c:835
void xmms_xform_outdata_type_copy(xmms_xform_t *xform)
Definition xform.c:452
gboolean xmms_xform_auxdata_has_val(xmms_xform_t *xform, const gchar *key)
Definition xform.c:815
enum xmms_xform_seek_mode_E xmms_xform_seek_mode_t
Seek direction argument.
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
gint xmms_xform_indata_get_int(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition xform.c:478
gboolean xmms_xform_auxdata_get_int(xmms_xform_t *xform, const gchar *key, gint32 *val)
Definition xform.c:821
#define XMMS_XFORM_MAX_LINE_SIZE
const xmms_stream_type_t * xmms_xform_get_out_stream_type(xmms_xform_t *xform)
Definition xform.c:1217
void xmms_xform_auxdata_set_bin(xmms_xform_t *xform, const gchar *key, gpointer data, gssize len)
Definition xform.c:779
gboolean xmms_xform_iseos(xmms_xform_t *xform)
Definition xform.c:1205
const char * xmms_xform_indata_get_str(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition xform.c:472
#define XMMS_XFORM_BROWSE_FLAG_DIR
void xmms_xform_browse_add_entry_property_str(xmms_xform_t *xform, const gchar *key, const gchar *value)
Definition xform.c:106
@ XMMS_XFORM_SEEK_CUR
gboolean xmms_medialib_decode_url(char *url)
Definition medialib.c:1475
gchar * xmms_medialib_url_encode(const gchar *path)
Definition medialib.c:1523
const gchar * xmms_plugin_shortname_get(const xmms_plugin_t *plugin)
Definition plugin.c:158
void xmms_plugin_foreach(xmms_plugin_type_t type, xmms_plugin_foreach_func_t func, gpointer user_data)
Definition plugin.c:406
xmms_config_property_t * xmms_plugin_config_lookup(xmms_plugin_t *plugin, const gchar *key)
Definition plugin.c:76
xmms_plugin_t * xmms_plugin_find(xmms_plugin_type_t type, const gchar *name)
Definition plugin.c:445
const char * xmms_stream_type_get_str(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition streamtype.c:148
gboolean xmms_stream_type_match(const xmms_stream_type_t *in_type, const xmms_stream_type_t *out_type)
Definition streamtype.c:210
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition streamtype.c:171
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)
Definition streamtype.c:71
xmms_plugin_type_t type
Definition xmms_plugin.h:33
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
struct match_state_St match_state_t
GList * xmms_xform_browse(const gchar *url, xmms_error_t *error)
Definition xform.c:277
gint xmms_xform_this_read(xmms_xform_t *xform, gpointer buf, gint siz, xmms_error_t *err)
Definition xform.c:943
void xmms_xform_outdata_type_set(xmms_xform_t *xform, xmms_stream_type_t *type)
Definition xform.c:445
xmms_xform_t * xmms_xform_chain_setup(xmms_medialib_entry_t entry, GList *goal_formats, gboolean rehash)
Definition xform.c:1388
xmms_xform_object_t * xmms_xform_object_init(void)
Definition xform.c:331
void xmms_xform_metadata_set_str(xmms_xform_t *xform, const char *key, const char *val)
Definition xform.c:520
gint xmms_xform_outtype_get_int(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition xform.c:504
const char * xmms_xform_shortname(xmms_xform_t *xform)
Definition xform.c:865
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
xmms_stream_type_t * xmms_xform_outtype_get(xmms_xform_t *xform)
Definition xform.c:484
gboolean xmms_xform_metadata_get_str(xmms_xform_t *xform, const char *key, const gchar **val)
Definition xform.c:580
struct xmms_xform_hotspot_St xmms_xform_hotspot_t
const char * xmms_xform_outtype_get_str(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition xform.c:498
const char * xmms_xform_indata_find_str(xmms_xform_t *xform, xmms_stream_type_key_t key)
Definition xform.c:459
xmms_xform_t * xmms_xform_find(xmms_xform_t *prev, xmms_medialib_entry_t entry, GList *goal_hints)
Definition xform.c:1183
void xmms_xform_auxdata_set_int(xmms_xform_t *xform, const char *key, int intval)
Definition xform.c:755
void xmms_xform_metadata_set_int(xmms_xform_t *xform, const char *key, int val)
Definition xform.c:511
gboolean xmms_xform_metadata_get_int(xmms_xform_t *xform, const char *key, gint32 *val)
Definition xform.c:564
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
#define READ_CHUNK
Definition xform.c:85
const GList * xmms_xform_goal_hints_get(xmms_xform_t *xform)
Definition xform.c:1223
GList * xmms_xform_browse_method(xmms_xform_t *xform, const gchar *url, xmms_error_t *error)
Definition xform.c:257
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
xmms_stream_type_t * xmms_xform_intype_get(xmms_xform_t *xform)
Definition xform.c:490
gboolean xmms_xform_plugin_can_browse(const xmms_xform_plugin_t *plugin)
gboolean xmms_xform_plugin_supports(const xmms_xform_plugin_t *plugin, xmms_stream_type_t *st, gint *priority)
gboolean xmms_xform_plugin_can_destroy(const xmms_xform_plugin_t *plugin)
void xmms_xform_plugin_destroy(const xmms_xform_plugin_t *plugin, xmms_xform_t *xform)
gboolean xmms_xform_plugin_browse(const xmms_xform_plugin_t *plugin, xmms_xform_t *xform, const gchar *url, xmms_error_t *error)
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)
gboolean xmms_xform_plugin_init(const xmms_xform_plugin_t *plugin, xmms_xform_t *xform)
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)
gboolean xmms_xform_plugin_can_seek(const xmms_xform_plugin_t *plugin)
gint xmms_natcmp(const gchar *str1, const gchar *str2)
Definition utils.c:150
struct xmms_config_property_St xmms_config_property_t
Definition xmms_config.h:26
#define xmms_log_error(fmt,...)
Definition xmms_log.h:35
#define xmms_log_info(fmt,...)
Definition xmms_log.h:34
#define XMMS_DBG(fmt,...)
Definition xmms_log.h:32
#define xmms_medialib_begin_write()
#define xmms_medialib_begin()
struct xmms_medialib_session_St xmms_medialib_session_t
#define XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED
#define XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLE_FMT
#define xmms_medialib_entry_status_set(session, e, st)
#define XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
#define XMMS_MEDIALIB_ENTRY_PROPERTY_CHAIN
#define XMMS_MEDIALIB_ENTRY_PROPERTY_CHANNELS
#define XMMS_MEDIALIB_ENTRY_PROPERTY_URL
#define XMMS_MEDIALIB_ENTRY_PROPERTY_TIMESPLAYED
#define XMMS_PLUGIN_SHORTNAME_MAX_LEN
Definition xmms_plugin.h:27
xmms_sample_format_t
Definition xmms_sample.h:25
@ XMMS_STREAM_TYPE_MIMETYPE
@ XMMS_STREAM_TYPE_FMT_FORMAT
@ XMMS_STREAM_TYPE_FMT_SAMPLERATE
@ XMMS_STREAM_TYPE_FMT_CHANNELS
@ XMMS_STREAM_TYPE_URL
@ XMMS_STREAM_TYPE_END
enum xmms_stream_type_key_E xmms_stream_type_key_t
struct xmms_stream_type_St xmms_stream_type_t
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
#define xmms_object_new(objtype, destroyfunc)
#define XMMS_OBJECT(p)
Definition xmms_object.h:77
#define xmms_object_ref(obj)
#define xmms_object_unref(obj)
struct xmms_xform_object_St xmms_xform_object_t
Definition xmms_xform.h:25
@ XMMS_ERROR_GENERIC
@ XMMS_MEDIALIB_ENTRY_STATUS_OK
@ XMMS_PLUGIN_TYPE_XFORM
#define MIN(a, b)
Definition xmmsc_util.h:36