limit gstreamer queue memory size
[vuplus_dvbapp] / lib / service / servicemp3.cpp
1 #ifdef HAVE_GSTREAMER
2
3         /* note: this requires gstreamer 0.10.x and a big list of plugins. */
4         /* it's currently hardcoded to use a big-endian alsasink as sink. */
5 #include <lib/base/eerror.h>
6 #include <lib/base/object.h>
7 #include <lib/base/ebase.h>
8 #include <string>
9 #include <lib/service/servicemp3.h>
10 #include <lib/service/service.h>
11 #include <lib/base/init_num.h>
12 #include <lib/base/init.h>
13 #include <gst/gst.h>
14
15 // eServiceFactoryMP3
16
17 eServiceFactoryMP3::eServiceFactoryMP3()
18 {
19         ePtr<eServiceCenter> sc;
20         
21         eServiceCenter::getPrivInstance(sc);
22         if (sc)
23         {
24                 std::list<std::string> extensions;
25                 extensions.push_back("mp3");
26                 extensions.push_back("ogg");
27                 extensions.push_back("mpg");
28                 extensions.push_back("vob");
29                 extensions.push_back("wav");
30                 extensions.push_back("wave");
31                 sc->addServiceFactory(eServiceFactoryMP3::id, this, extensions);
32         }
33
34         m_service_info = new eStaticServiceMP3Info();
35 }
36
37 eServiceFactoryMP3::~eServiceFactoryMP3()
38 {
39         ePtr<eServiceCenter> sc;
40         
41         eServiceCenter::getPrivInstance(sc);
42         if (sc)
43                 sc->removeServiceFactory(eServiceFactoryMP3::id);
44 }
45
46 DEFINE_REF(eServiceFactoryMP3)
47
48         // iServiceHandler
49 RESULT eServiceFactoryMP3::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
50 {
51                 // check resources...
52         ptr = new eServiceMP3(ref.path.c_str());
53         return 0;
54 }
55
56 RESULT eServiceFactoryMP3::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
57 {
58         ptr=0;
59         return -1;
60 }
61
62 RESULT eServiceFactoryMP3::list(const eServiceReference &, ePtr<iListableService> &ptr)
63 {
64         ptr=0;
65         return -1;
66 }
67
68 RESULT eServiceFactoryMP3::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
69 {
70         ptr = m_service_info;
71         return 0;
72 }
73
74 RESULT eServiceFactoryMP3::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
75 {
76         ptr = 0;
77         return -1;
78 }
79
80
81 // eStaticServiceMP3Info
82
83
84 // eStaticServiceMP3Info is seperated from eServiceMP3 to give information
85 // about unopened files.
86
87 // probably eServiceMP3 should use this class as well, and eStaticServiceMP3Info
88 // should have a database backend where ID3-files etc. are cached.
89 // this would allow listing the mp3 database based on certain filters.
90
91 DEFINE_REF(eStaticServiceMP3Info)
92
93 eStaticServiceMP3Info::eStaticServiceMP3Info()
94 {
95 }
96
97 RESULT eStaticServiceMP3Info::getName(const eServiceReference &ref, std::string &name)
98 {
99         size_t last = ref.path.rfind('/');
100         if (last != std::string::npos)
101                 name = ref.path.substr(last+1);
102         else
103                 name = ref.path;
104         return 0;
105 }
106
107 int eStaticServiceMP3Info::getLength(const eServiceReference &ref)
108 {
109         return -1;
110 }
111
112 // eServiceMP3
113
114 eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eApp, 1)
115 {
116         m_stream_tags = 0;
117         CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
118         GstElement *source = 0;
119         
120         GstElement *filter = 0, *decoder = 0, *conv = 0, *flt = 0, *sink = 0; /* for audio */
121         
122         GstElement *audio = 0, *queue_audio = 0, *video = 0, *queue_video = 0, *mpegdemux = 0;
123         
124         m_state = stIdle;
125         eDebug("SERVICEMP3 construct!");
126         
127                 /* FIXME: currently, decodebin isn't possible for 
128                    video streams. in that case, make a manual pipeline. */
129
130         const char *ext = strrchr(filename, '.');
131         if (!ext)
132                 ext = filename;
133
134         int is_mpeg_ps = !(strcasecmp(ext, ".mpeg") && strcasecmp(ext, ".mpg") && strcasecmp(ext, ".vob") && strcasecmp(ext, ".bin"));
135         int is_mpeg_ts = !strcasecmp(ext, ".ts");
136         int is_mp3 = !strcasecmp(ext, ".mp3"); /* force mp3 instead of decodebin */
137         int is_video = is_mpeg_ps || is_mpeg_ts;
138         int is_streaming = !strncmp(filename, "http://", 7);
139         
140         eDebug("filename: %s, is_mpeg_ps: %d, is_mpeg_ts: %d, is_video: %d, is_streaming: %d, is_mp3: %d", filename, is_mpeg_ps, is_mpeg_ts, is_video, is_streaming, is_mp3);
141         
142         int is_audio = !is_video;
143         
144         int all_ok = 0;
145
146         m_gst_pipeline = gst_pipeline_new ("audio-player");
147         if (!m_gst_pipeline)
148                 eWarning("failed to create pipeline");
149
150         if (!is_streaming)
151                 source = gst_element_factory_make ("filesrc", "file-source");
152         else
153         {
154                 source = gst_element_factory_make ("neonhttpsrc", "http-source");
155                 if (source)
156                         g_object_set (G_OBJECT (source), "automatic-redirect", TRUE, NULL);
157         }
158
159         if (!source)
160                 eWarning("failed to create %s", is_streaming ? "neonhttpsrc" : "filesrc");
161         else
162                                 /* configure source */
163                 g_object_set (G_OBJECT (source), "location", filename, NULL);
164
165         if (is_audio)
166         {
167                         /* filesrc -> decodebin -> audioconvert -> capsfilter -> alsasink */
168                 const char *decodertype = is_mp3 ? "mad" : "decodebin";
169
170                 decoder = gst_element_factory_make (decodertype, "decoder");
171                 if (!decoder)
172                         eWarning("failed to create %s decoder", decodertype);
173
174                         /* mp3 decoding needs id3demux to extract ID3 data. 'decodebin' would do that internally. */
175                 if (is_mp3)
176                 {
177                         filter = gst_element_factory_make ("id3demux", "filter");
178                         if (!filter)
179                                 eWarning("failed to create id3demux");
180                 }
181
182                 conv = gst_element_factory_make ("audioconvert", "converter");
183                 if (!conv)
184                         eWarning("failed to create audioconvert");
185
186                 flt = gst_element_factory_make ("capsfilter", "flt");
187                 if (!flt)
188                         eWarning("failed to create capsfilter");
189
190                         /* for some reasons, we need to set the sample format to depth/width=16, because auto negotiation doesn't work. */
191                         /* endianness, however, is not required to be set anymore. */
192                 if (flt)
193                 {
194                         GstCaps *caps = gst_caps_new_simple("audio/x-raw-int", /* "endianness", G_TYPE_INT, 4321, */ "depth", G_TYPE_INT, 16, "width", G_TYPE_INT, 16, "channels", G_TYPE_INT, 2, (char*)0);
195                         g_object_set (G_OBJECT (flt), "caps", caps, (char*)0);
196                         gst_caps_unref(caps);
197                 }
198
199                 sink = gst_element_factory_make ("alsasink", "alsa-output");
200                 if (!sink)
201                         eWarning("failed to create osssink");
202
203                 if (source && decoder && conv && sink)
204                         all_ok = 1;
205         } else /* is_video */
206         {
207                         /* filesrc -> mpegdemux -> | queue_audio -> dvbaudiosink
208                                                    | queue_video -> dvbvideosink */
209
210                 audio = gst_element_factory_make("dvbaudiosink", "audio");
211                 queue_audio = gst_element_factory_make("queue", "queue_audio");
212                 
213                 video = gst_element_factory_make("dvbvideosink", "video");
214                 queue_video = gst_element_factory_make("queue", "queue_video");
215                 
216                 if (is_mpeg_ps)
217                         mpegdemux = gst_element_factory_make("flupsdemux", "mpegdemux");
218                 else
219                         mpegdemux = gst_element_factory_make("flutsdemux", "mpegdemux");
220                         
221                 if (!mpegdemux)
222                 {
223                         eDebug("fluendo mpegdemux not available, falling back to mpegdemux\n");
224                         mpegdemux = gst_element_factory_make("mpegdemux", "mpegdemux");
225                 }
226                 
227                 eDebug("audio: %p, queue_audio %p, video %p, queue_video %p, mpegdemux %p", audio, queue_audio, video, queue_video, mpegdemux);
228                 if (audio && queue_audio && video && queue_video && mpegdemux)
229                 {
230                         g_object_set (G_OBJECT (queue_audio), "max-size-bytes", 256*1024, NULL);
231                         g_object_set (G_OBJECT (queue_audio), "max-size-buffers", 0, NULL);
232                         g_object_set (G_OBJECT (queue_audio), "max-size-time", (guint64)0, NULL);
233                         g_object_set (G_OBJECT (queue_video), "max-size-buffers", 0, NULL);
234                         g_object_set (G_OBJECT (queue_video), "max-size-bytes", 2*1024*1024, NULL);
235                         g_object_set (G_OBJECT (queue_video), "max-size-time", (guint64)0, NULL);
236                         all_ok = 1;
237                 }
238         }
239         
240         if (m_gst_pipeline && all_ok)
241         {
242                 gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (m_gst_pipeline)), gstBusSyncHandler, this);
243
244                 if (is_audio)
245                 {
246                         if (!is_mp3)
247                         {
248                                         /* decodebin has dynamic pads. When they get created, we connect them to the audio bin */
249                                 g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK(gstCBnewPad), this);
250                                 g_signal_connect (decoder, "unknown-type", G_CALLBACK(gstCBunknownType), this);
251                         }
252
253                                 /* gst_bin will take the 'floating references' */
254                         gst_bin_add_many (GST_BIN (m_gst_pipeline),
255                                                 source, decoder, NULL);
256
257                         if (filter)
258                         {
259                                         /* id3demux also has dynamic pads, which need to be connected to the decoder (this is done in the 'gstCBfilterPadAdded' CB) */
260                                 gst_bin_add(GST_BIN(m_gst_pipeline), filter);
261                                 gst_element_link(source, filter);
262                                 m_decoder = decoder;
263                                 g_signal_connect (filter, "pad-added", G_CALLBACK(gstCBfilterPadAdded), this);
264                         } else
265                                         /* in decodebin's case we can just connect the source with the decodebin, and decodebin will take care about id3demux (or whatever is required) */
266                                 gst_element_link(source, decoder);
267
268                                 /* create audio bin with the audioconverter, the capsfilter and the audiosink */
269                         m_gst_audio = gst_bin_new ("audiobin");
270
271                         GstPad *audiopad = gst_element_get_pad (conv, "sink");
272                         gst_bin_add_many(GST_BIN(m_gst_audio), conv, flt, sink, (char*)0);
273                         gst_element_link_many(conv, flt, sink, (char*)0);
274                         gst_element_add_pad(m_gst_audio, gst_ghost_pad_new ("sink", audiopad));
275                         gst_object_unref(audiopad);
276                         gst_bin_add (GST_BIN(m_gst_pipeline), m_gst_audio);
277
278                                 /* in mad's case, we can directly connect the decoder to the audiobin. otherwise, we do this in gstCBnewPad */
279                         if (is_mp3)
280                                 gst_element_link(decoder, m_gst_audio);
281                 } else
282                 {
283                         gst_bin_add_many(GST_BIN(m_gst_pipeline), source, mpegdemux, audio, queue_audio, video, queue_video, NULL);
284                         gst_element_link(source, mpegdemux);
285                         gst_element_link(queue_audio, audio);
286                         gst_element_link(queue_video, video);
287                         
288                         m_gst_audioqueue = queue_audio;
289                         m_gst_videoqueue = queue_video;
290                         
291                         g_signal_connect(mpegdemux, "pad-added", G_CALLBACK (gstCBpadAdded), this);
292                 }
293         } else
294         {
295                 if (m_gst_pipeline)
296                         gst_object_unref(GST_OBJECT(m_gst_pipeline));
297                 if (source)
298                         gst_object_unref(GST_OBJECT(source));
299                 if (decoder)
300                         gst_object_unref(GST_OBJECT(decoder));
301                 if (conv)
302                         gst_object_unref(GST_OBJECT(conv));
303                 if (sink)
304                         gst_object_unref(GST_OBJECT(sink));
305
306                 if (audio)
307                         gst_object_unref(GST_OBJECT(audio));
308                 if (queue_audio)
309                         gst_object_unref(GST_OBJECT(queue_audio));
310                 if (video)
311                         gst_object_unref(GST_OBJECT(video));
312                 if (queue_video)
313                         gst_object_unref(GST_OBJECT(queue_video));
314                 if (mpegdemux)
315                         gst_object_unref(GST_OBJECT(mpegdemux));
316
317                 eDebug("sorry, can't play.");
318                 m_gst_pipeline = 0;
319         }
320         
321         gst_element_set_state (m_gst_pipeline, GST_STATE_PLAYING);
322 }
323
324 eServiceMP3::~eServiceMP3()
325 {
326         if (m_state == stRunning)
327                 stop();
328         
329         if (m_stream_tags)
330                 gst_tag_list_free(m_stream_tags);
331         
332         if (m_gst_pipeline)
333         {
334                 gst_object_unref (GST_OBJECT (m_gst_pipeline));
335                 eDebug("SERVICEMP3 destruct!");
336         }
337 }
338
339 DEFINE_REF(eServiceMP3);        
340
341 RESULT eServiceMP3::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
342 {
343         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
344         return 0;
345 }
346
347 RESULT eServiceMP3::start()
348 {
349         assert(m_state == stIdle);
350         
351         m_state = stRunning;
352         if (m_gst_pipeline)
353         {
354                 eDebug("starting pipeline");
355                 gst_element_set_state (m_gst_pipeline, GST_STATE_PLAYING);
356         }
357         m_event(this, evStart);
358         return 0;
359 }
360
361 RESULT eServiceMP3::stop()
362 {
363         assert(m_state != stIdle);
364         if (m_state == stStopped)
365                 return -1;
366         printf("MP3: %s stop\n", m_filename.c_str());
367         gst_element_set_state(m_gst_pipeline, GST_STATE_NULL);
368         m_state = stStopped;
369         return 0;
370 }
371
372 RESULT eServiceMP3::setTarget(int target)
373 {
374         return -1;
375 }
376
377 RESULT eServiceMP3::pause(ePtr<iPauseableService> &ptr)
378 {
379         ptr=this;
380         return 0;
381 }
382
383 RESULT eServiceMP3::setSlowMotion(int ratio)
384 {
385         return -1;
386 }
387
388 RESULT eServiceMP3::setFastForward(int ratio)
389 {
390         return -1;
391 }
392   
393                 // iPausableService
394 RESULT eServiceMP3::pause()
395 {
396         if (!m_gst_pipeline)
397                 return -1;
398         gst_element_set_state(m_gst_pipeline, GST_STATE_PAUSED);
399         return 0;
400 }
401
402 RESULT eServiceMP3::unpause()
403 {
404         if (!m_gst_pipeline)
405                 return -1;
406         gst_element_set_state(m_gst_pipeline, GST_STATE_PLAYING);
407         return 0;
408 }
409
410         /* iSeekableService */
411 RESULT eServiceMP3::seek(ePtr<iSeekableService> &ptr)
412 {
413         ptr = this;
414         return 0;
415 }
416
417 RESULT eServiceMP3::getLength(pts_t &pts)
418 {
419         if (!m_gst_pipeline)
420                 return -1;
421         if (m_state != stRunning)
422                 return -1;
423         
424         GstFormat fmt = GST_FORMAT_TIME;
425         gint64 len;
426         
427         if (!gst_element_query_duration(m_gst_pipeline, &fmt, &len))
428                 return -1;
429         
430                 /* len is in nanoseconds. we have 90 000 pts per second. */
431         
432         pts = len / 11111;
433         return 0;
434 }
435
436 RESULT eServiceMP3::seekTo(pts_t to)
437 {
438         if (!m_gst_pipeline)
439                 return -1;
440
441                 /* convert pts to nanoseconds */
442         gint64 time_nanoseconds = to * 11111LL;
443         if (!gst_element_seek (m_gst_pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
444                 GST_SEEK_TYPE_SET, time_nanoseconds,
445                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
446         {
447                 eDebug("SEEK failed");
448                 return -1;
449         }
450         return 0;
451 }
452
453 RESULT eServiceMP3::seekRelative(int direction, pts_t to)
454 {
455         if (!m_gst_pipeline)
456                 return -1;
457
458         pause();
459
460         pts_t ppos;
461         getPlayPosition(ppos);
462         ppos += to * direction;
463         if (ppos < 0)
464                 ppos = 0;
465         seekTo(ppos);
466         
467         unpause();
468
469         return 0;
470 }
471
472 RESULT eServiceMP3::getPlayPosition(pts_t &pts)
473 {
474         if (!m_gst_pipeline)
475                 return -1;
476         if (m_state != stRunning)
477                 return -1;
478         
479         GstFormat fmt = GST_FORMAT_TIME;
480         gint64 len;
481         
482         if (!gst_element_query_position(m_gst_pipeline, &fmt, &len))
483                 return -1;
484         
485                 /* len is in nanoseconds. we have 90 000 pts per second. */
486         pts = len / 11111;
487         return 0;
488 }
489
490 RESULT eServiceMP3::setTrickmode(int trick)
491 {
492                 /* trickmode currently doesn't make any sense for us. */
493         return -1;
494 }
495
496 RESULT eServiceMP3::isCurrentlySeekable()
497 {
498         return 1;
499 }
500
501 RESULT eServiceMP3::info(ePtr<iServiceInformation>&i)
502 {
503         i = this;
504         return 0;
505 }
506
507 RESULT eServiceMP3::getName(std::string &name)
508 {
509         name = m_filename;
510         size_t n = name.rfind('/');
511         if (n != std::string::npos)
512                 name = name.substr(n + 1);
513         return 0;
514 }
515
516 int eServiceMP3::getInfo(int w)
517 {
518         switch (w)
519         {
520         case sTitle:
521         case sArtist:
522         case sAlbum:
523         case sComment:
524         case sTracknumber:
525         case sGenre:
526                 return resIsString;
527
528         default:
529                 return resNA;
530         }
531 }
532
533 std::string eServiceMP3::getInfoString(int w)
534 {
535         gchar *tag = 0;
536         switch (w)
537         {
538         case sTitle:
539                 tag = GST_TAG_TITLE;
540                 break;
541         case sArtist:
542                 tag = GST_TAG_ARTIST;
543                 break;
544         case sAlbum:
545                 tag = GST_TAG_ALBUM;
546                 break;
547         case sComment:
548                 tag = GST_TAG_COMMENT;
549                 break;
550         case sTracknumber:
551                 tag = GST_TAG_TRACK_NUMBER;
552                 break;
553         case sGenre:
554                 tag = GST_TAG_GENRE;
555                 break;
556         default:
557                 return "";
558         }
559         
560         if (!m_stream_tags || !tag)
561                 return "";
562         
563         gchar *value;
564         
565         if (gst_tag_list_get_string(m_stream_tags, tag, &value))
566         {
567                 std::string res = value;
568                 g_free(value);
569                 return res;
570         }
571         
572         return "";
573 }
574
575
576                 void foreach(const GstTagList *list, const gchar *tag, gpointer user_data)
577                 {
578                         if (tag)
579                                 eDebug("Tag: %c%c%c%c", tag[0], tag[1], tag[2], tag[3]);
580                         
581                 }
582
583 void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
584 {
585         if (msg)
586         {
587                 gchar *string = gst_structure_to_string(gst_message_get_structure(msg));
588                 eDebug("gst_message: %s", string);
589                 g_free(string);
590         }
591         
592         switch (GST_MESSAGE_TYPE (msg))
593         {
594         case GST_MESSAGE_EOS:
595                 m_event((iPlayableService*)this, evEOF);
596                 break;
597         case GST_MESSAGE_ERROR:
598         {
599                 gchar *debug;
600                 GError *err;
601                 gst_message_parse_error (msg, &err, &debug);
602                 g_free (debug);
603                 eWarning("Gstreamer error: %s", err->message);
604                 g_error_free(err);
605                         /* TODO: signal error condition to user */
606                 break;
607         }
608         case GST_MESSAGE_TAG:
609         {
610                 GstTagList *tags, *result;
611                 gst_message_parse_tag(msg, &tags);
612
613                 result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_PREPEND);
614                 if (result)
615                 {
616                         if (m_stream_tags)
617                                 gst_tag_list_free(m_stream_tags);
618                         m_stream_tags = result;
619                 }
620                 gst_tag_list_free(tags);
621                 
622                 m_event((iPlayableService*)this, evUpdatedInfo);
623                 break;
624         }
625         default:
626                 break;
627         }
628 }
629
630 GstBusSyncReply eServiceMP3::gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data)
631 {
632         eServiceMP3 *_this = (eServiceMP3*)user_data;
633         _this->m_pump.send(1);
634                 /* wake */
635         return GST_BUS_PASS;
636 }
637
638 void eServiceMP3::gstCBpadAdded(GstElement *decodebin, GstPad *pad, gpointer user_data)
639 {
640         eServiceMP3 *_this = (eServiceMP3*)user_data;
641         
642         gchar *name;
643         name = gst_pad_get_name (pad);
644         g_print ("A new pad %s was created\n", name);
645         if (!strncmp(name, "audio_", 6)) // mpegdemux uses video_nn with n=0,1,.., flupsdemux uses stream id
646                 gst_pad_link(pad, gst_element_get_pad (_this->m_gst_audioqueue, "sink"));
647         if (!strncmp(name, "video_", 6))
648                 gst_pad_link(pad, gst_element_get_pad (_this->m_gst_videoqueue, "sink"));
649         g_free (name);
650         
651 }
652
653 void eServiceMP3::gstCBfilterPadAdded(GstElement *filter, GstPad *pad, gpointer user_data)
654 {
655         eServiceMP3 *_this = (eServiceMP3*)user_data;
656         gst_pad_link(pad, gst_element_get_pad (_this->m_decoder, "sink"));
657 }
658
659 void eServiceMP3::gstCBnewPad(GstElement *decodebin, GstPad *pad, gboolean last, gpointer user_data)
660 {
661         eServiceMP3 *_this = (eServiceMP3*)user_data;
662         GstCaps *caps;
663         GstStructure *str;
664         GstPad *audiopad;
665
666         /* only link once */
667         audiopad = gst_element_get_pad (_this->m_gst_audio, "sink");
668         if (GST_PAD_IS_LINKED (audiopad)) {
669                 eDebug("audio already linked!");
670                 g_object_unref (audiopad);
671                 return;
672         }
673
674         /* check media type */
675         caps = gst_pad_get_caps (pad);
676         str = gst_caps_get_structure (caps, 0);
677         eDebug("gst new pad! %s", gst_structure_get_name (str));
678         
679         if (!g_strrstr (gst_structure_get_name (str), "audio")) {
680                 gst_caps_unref (caps);
681                 gst_object_unref (audiopad);
682                 return;
683         }
684         
685         gst_caps_unref (caps);
686         gst_pad_link (pad, audiopad);
687 }
688
689 void eServiceMP3::gstCBunknownType(GstElement *decodebin, GstPad *pad, GstCaps *caps, gpointer user_data)
690 {
691         eServiceMP3 *_this = (eServiceMP3*)user_data;
692         GstStructure *str;
693
694         /* check media type */
695         caps = gst_pad_get_caps (pad);
696         str = gst_caps_get_structure (caps, 0);
697         eDebug("unknown type: %s - this can't be decoded.", gst_structure_get_name (str));
698         gst_caps_unref (caps);
699 }
700
701 void eServiceMP3::gstPoll(const int&)
702 {
703                 /* ok, we have a serious problem here. gstBusSyncHandler sends 
704                    us the wakup signal, but likely before it was posted.
705                    the usleep, an EVIL HACK (DON'T DO THAT!!!) works around this.
706                    
707                    I need to understand the API a bit more to make this work 
708                    proplerly. */
709         usleep(1);
710         
711         GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_pipeline));
712         GstMessage *message;
713         while ((message = gst_bus_pop (bus)))
714         {
715                 gstBusCall(bus, message);
716                 gst_message_unref (message);
717         }
718 }
719
720 eAutoInitPtr<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::service+1, "eServiceFactoryMP3");
721 #else
722 #warning gstreamer not available, not building media player
723 #endif