implement dispose method to stop leaking of gst pipeline clock socket
[gst-plugin-dvbmediasink.git] / src / gstdvbaudiosink.c
1 /*
2  * GStreamer DVB Media Sink
3  * Copyright 2006 Felix Domke <tmbinc@elitedvb.net>
4  * based on code by:
5  * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
6  * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
7  * 
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Alternatively, the contents of this file may be used under the
27  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28  * which case the following provisions apply instead of the ones
29  * mentioned above:
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of the GNU Library General Public
33  * License as published by the Free Software Foundation; either
34  * version 2 of the License, or (at your option) any later version.
35  *
36  * This library is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39  * Library General Public License for more details.
40  *
41  * You should have received a copy of the GNU Library General Public
42  * License along with this library; if not, write to the
43  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44  * Boston, MA 02111-1307, USA.
45  */
46
47 /**
48  * SECTION:element-plugin
49  *
50  * <refsect2>
51  * <title>Example launch line</title>
52  * <para>
53  * <programlisting>
54  * gst-launch -v -m audiotestsrc ! plugin ! fakesink silent=TRUE
55  * </programlisting>
56  * </para>
57  * </refsect2>
58  */
59
60 #ifdef HAVE_CONFIG_H
61 #include <config.h>
62 #endif
63 #include <unistd.h>
64 #include <string.h>
65 #include <sys/ioctl.h>
66 #include <sys/socket.h>
67 #include <linux/dvb/audio.h>
68 #include <linux/dvb/video.h>
69 #include <fcntl.h>
70 #include <poll.h>
71
72 #include <gst/gst.h>
73
74 #include "gstdvbaudiosink.h"
75
76 /* We add a control socket as in fdsrc to make it shutdown quickly when it's blocking on the fd.
77  * Poll is used to determine when the fd is ready for use. When the element state is changed,
78  * it happens from another thread while fdsink is select'ing on the fd. The state-change thread 
79  * sends a control message, so fdsink wakes up and changes state immediately otherwise
80  * it would stay blocked until it receives some data. */
81
82 /* the poll call is also performed on the control sockets, that way
83  * we can send special commands to unblock the select call */
84 #define CONTROL_STOP            'S'                     /* stop the select call */
85 #define CONTROL_SOCKETS(sink)   sink->control_sock
86 #define WRITE_SOCKET(sink)      sink->control_sock[1]
87 #define READ_SOCKET(sink)       sink->control_sock[0]
88
89 #define SEND_COMMAND(sink, command)                     \
90 G_STMT_START {                                          \
91         unsigned char c; c = command;                   \
92         write (WRITE_SOCKET(sink), &c, 1);              \
93 } G_STMT_END
94
95 #define READ_COMMAND(sink, command, res)                \
96 G_STMT_START {                                          \
97         res = read(READ_SOCKET(sink), &command, 1);     \
98 } G_STMT_END
99
100 #ifndef AUDIO_GET_PTS
101 #define AUDIO_GET_PTS           _IOR('o', 19, gint64)
102 #endif
103
104 GST_DEBUG_CATEGORY_STATIC (dvbaudiosink_debug);
105 #define GST_CAT_DEFAULT dvbaudiosink_debug
106
107 #define GST_DVBAUDIOSINK_GET_PRIVATE(obj)  \
108    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_DVBAUDIOSINK, GstDVBAudioSinkPrivate))
109
110 struct _GstDVBAudioSinkPrivate
111 {
112
113         gboolean bypass_set;
114         hardwaretype_t model;
115
116 };
117
118 /* Filter signals and args */
119 enum {
120         /* FILL ME */
121         LAST_SIGNAL
122 };
123
124 enum {
125         ARG_0,
126         ARG_SILENT
127 };
128
129 guint AdtsSamplingRates[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0 };
130
131 static GstStaticPadTemplate sink_factory =
132 GST_STATIC_PAD_TEMPLATE (
133         "sink",
134         GST_PAD_SINK,
135         GST_PAD_ALWAYS,
136         GST_STATIC_CAPS ("audio/mpeg; "
137                 "audio/x-ac3; "
138                 "audio/x-private1-ac3; "
139                 "audio/x-dts; "
140                 "audio/x-private1-dts" )
141 );
142
143 enum
144 {
145   PROP_0,
146   PROP_BUFFER_TIME,
147   PROP_LATENCY_TIME,
148   PROP_PROVIDE_CLOCK,
149   PROP_SLAVE_METHOD
150 };
151
152 #define DEFAULT_PROVIDE_CLOCK   TRUE
153 #define DEFAULT_SLAVE_METHOD    GST_BASE_AUDIO_SINK_SLAVE_SKEW
154
155 #define DEBUG_INIT(bla) \
156         GST_DEBUG_CATEGORY_INIT (dvbaudiosink_debug, "dvbaudiosink", 0, "dvbaudiosink element");
157
158 GST_BOILERPLATE_FULL (GstDVBAudioSink, gst_dvbaudiosink, GstBaseSink, GST_TYPE_BASE_SINK, DEBUG_INIT);
159
160 static void     gst_dvbaudiosink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
161 static void     gst_dvbaudiosink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
162 static gboolean gst_dvbaudiosink_start (GstBaseSink * sink);
163 static gboolean gst_dvbaudiosink_stop (GstBaseSink * sink);
164 static gboolean gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event);
165 static GstFlowReturn gst_dvbaudiosink_render (GstBaseSink * sink, GstBuffer * buffer);
166 static gboolean gst_dvbaudiosink_query (GstElement * element, GstQuery * query);
167 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink);
168 static gboolean gst_dvbaudiosink_unlock_stop (GstBaseSink * basesink);
169 static gboolean gst_dvbaudiosink_set_caps (GstBaseSink * sink, GstCaps * caps);
170 static GstCaps *gst_dvbaudiosink_get_caps (GstBaseSink * bsink);
171 static GstClock * gst_dvbaudiosink_provide_clock (GstElement * elem);
172 static GstClockTime  gst_dvbaudiosink_get_time (GstClock * clock, GstDVBAudioSink * sink);
173 static void gst_dvbaudiosink_dispose (GObject * object);
174
175 static void
176 gst_dvbaudiosink_base_init (gpointer klass)
177 {
178         static GstElementDetails element_details = {
179                 "A DVB audio sink",
180                 "Generic/DVBAudioSink",
181                 "Outputs a MPEG2 PES / ES into a DVB audio device for hardware playback",
182                 "Felix Domke <tmbinc@elitedvb.net>"
183         };
184         GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
185
186         gst_element_class_add_pad_template (element_class,
187                 gst_static_pad_template_get (&sink_factory));
188         gst_element_class_set_details (element_class, &element_details);
189 }
190
191 /* initialize the plugin's class */
192 static void
193 gst_dvbaudiosink_class_init (GstDVBAudioSinkClass *klass)
194 {
195         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
196         GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
197         g_type_class_add_private (klass, sizeof (GstDVBAudioSinkPrivate));
198         
199         gobject_class->set_property = gst_dvbaudiosink_set_property;
200         gobject_class->get_property = gst_dvbaudiosink_get_property;
201         
202         gobject_class = G_OBJECT_CLASS (klass);
203         g_object_class_install_property (gobject_class, ARG_SILENT, g_param_spec_boolean
204                 ("silent", "Silent", "Produce verbose output ?", FALSE, G_PARAM_READWRITE));
205         g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK, g_param_spec_boolean
206                 ("provide-clock", "Provide Clock", "Provide a clock to be used as the global pipeline clock", DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207
208         gstbasesink_class->get_times = NULL;
209         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_start);
210         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_stop);
211         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_render);
212         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_event);
213         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_unlock);
214         gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR ( gst_dvbaudiosink_unlock_stop);
215         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_set_caps);
216         gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_get_caps);
217         gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_dispose);
218         GST_ELEMENT_CLASS (klass)->provide_clock = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_provide_clock);
219         GST_ELEMENT_CLASS (klass)->query = GST_DEBUG_FUNCPTR(gst_dvbaudiosink_query);
220 }
221
222 /* initialize the new element
223  * instantiate pads and add them to element
224  * set functions
225  * initialize structure
226  */
227 static void
228 gst_dvbaudiosink_init (GstDVBAudioSink *klass, GstDVBAudioSinkClass * gclass)
229 {
230         klass->priv = GST_DVBAUDIOSINK_GET_PRIVATE (klass);
231         klass->priv->bypass_set = FALSE;
232         klass->provide_clock = DEFAULT_PROVIDE_CLOCK;
233         klass->silent = FALSE;
234         klass->aac_adts_header_valid = FALSE;
235
236         GST_BASE_SINK (klass)->sync = TRUE;
237
238         klass->provided_clock = gst_audio_clock_new ("GstDVBAudioSinkClock", (GstAudioClockGetTimeFunc) gst_dvbaudiosink_get_time, klass);
239
240         klass->priv->model = DMLEGACY;
241         int fd = open("/proc/stb/info/model", O_RDONLY);
242         if ( fd > 0 )
243         {
244                 gchar string[8] = { 0, };
245                 ssize_t rd = read(fd, string, 6);
246                 if ( rd >= 5 )
247                 {
248                         if ( !strncasecmp(string, "DM7025", 6) )
249                                 klass->priv->model = DM7025;
250                         else if ( !strncasecmp(string, "DM8000", 6) )
251                                 klass->priv->model = DM8000;
252                         else if ( !strncasecmp(string, "DM800", 5) )
253                                 klass->priv->model = DM800;
254                 }
255                 close(fd);
256                 GST_INFO_OBJECT (klass, "found hardware model %s (%i)",string,klass->priv->model);
257         }
258 }
259
260 static void gst_dvbaudiosink_dispose (GObject * object)
261 {
262         GstDVBAudioSink *self;
263         
264         self = GST_DVBAUDIOSINK (object);
265         
266         if (self->provided_clock)
267                 gst_object_unref (self->provided_clock);
268         self->provided_clock = NULL;
269
270         close (READ_SOCKET (self));
271         close (WRITE_SOCKET (self));
272         READ_SOCKET (self) = -1;
273         WRITE_SOCKET (self) = -1;
274
275         G_OBJECT_CLASS (parent_class)->dispose (object);
276 }
277
278 static GstClock *
279 gst_dvbaudiosink_provide_clock (GstElement * element)
280 {
281   GstClock *clock;
282   GstDVBAudioSink *self = GST_DVBAUDIOSINK (element);
283
284   GST_OBJECT_LOCK (self);
285   if (!self->provide_clock)
286     goto clock_disabled;
287
288   clock = GST_CLOCK_CAST (gst_object_ref (self->provided_clock));
289   GST_OBJECT_UNLOCK (self);
290
291   return clock;
292
293   /* ERRORS */
294 clock_disabled:
295   {
296     GST_DEBUG_OBJECT (self, "clock provide disabled");
297     GST_OBJECT_UNLOCK (self);
298     return NULL;
299   }
300 }
301
302 static void
303 gst_dvbaudiosink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
304 {
305         GstDVBAudioSink *self;
306
307         g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
308         self = GST_DVBAUDIOSINK (object);
309
310         switch (prop_id)
311         {
312         case ARG_SILENT:
313                 self->silent = g_value_get_boolean (value);
314                 break;
315         case PROP_PROVIDE_CLOCK:
316                 gst_dvbaudiosink_set_provide_clock (self, g_value_get_boolean (value));
317                 break;
318         default:
319                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320                 break;
321         }
322 }
323
324 static void
325 gst_dvbaudiosink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
326 {
327         GstDVBAudioSink *self;
328
329         g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
330         self = GST_DVBAUDIOSINK (object);
331
332         switch (prop_id) {
333         case ARG_SILENT:
334                 g_value_set_boolean (value, self->silent);
335                 break;
336         case PROP_PROVIDE_CLOCK:
337                 g_value_set_boolean (value, gst_dvbaudiosink_get_provide_clock (self));
338                 break;
339         default:
340                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341                 break;
342         }
343 }
344
345 static gboolean
346 gst_dvbaudiosink_query (GstElement * element, GstQuery * query)
347 {
348         GstDVBAudioSink *self = GST_DVBAUDIOSINK (element);
349
350         switch (GST_QUERY_TYPE (query)) {
351         case GST_QUERY_POSITION:
352         {
353                 gint64 cur = 0, res = 0;
354                 static gint64 last_pos = 0;
355                 GstFormat format;
356
357                 gst_query_parse_position (query, &format, NULL);
358
359                 if (format != GST_FORMAT_TIME)
360                         goto query_default;
361
362                 ioctl(self->fd, AUDIO_GET_PTS, &cur);
363
364                 /* workaround until driver fixed */
365                 if (cur)
366                         last_pos = cur;
367                 else
368                         cur = last_pos;
369
370                 res = cur *11111;
371
372                 gst_query_set_position (query, format, res);
373
374                 GST_LOG_OBJECT (self, "GST_QUERY_POSITION pts=%lld: %" G_GUINT64_FORMAT ", time: %" GST_TIME_FORMAT, cur, GST_TIME_ARGS (res));
375                 return TRUE;
376         }
377         default:
378 query_default:
379                 return GST_ELEMENT_CLASS (parent_class)->query (element, query);
380         }
381 }
382
383 static GstClockTime
384 gst_dvbaudiosink_get_time (GstClock * clock, GstDVBAudioSink * sink)
385 {
386         GstClockTime result;
387         
388         gint64 cur = 0;
389         ioctl(sink->fd, AUDIO_GET_PTS, &cur);
390
391         result = cur * 11111;
392
393         GST_LOG_OBJECT (sink, "get_time pts=%lld: %" G_GUINT64_FORMAT ", time: %" GST_TIME_FORMAT, cur, GST_TIME_ARGS (result));
394
395         return result;
396 }
397
398 void
399 gst_dvbaudiosink_set_provide_clock (GstDVBAudioSink * sink, gboolean provide)
400 {
401   g_return_if_fail (GST_IS_DVBAUDIOSINK (sink));
402
403   GST_OBJECT_LOCK (sink);
404   sink->provide_clock = provide;
405   GST_OBJECT_UNLOCK (sink);
406 }
407
408 gboolean
409 gst_dvbaudiosink_get_provide_clock (GstDVBAudioSink * sink)
410 {
411   gboolean result;
412
413   g_return_val_if_fail (GST_IS_DVBAUDIOSINK (sink), FALSE);
414
415   GST_OBJECT_LOCK (sink);
416   result = sink->provide_clock;
417   GST_OBJECT_UNLOCK (sink);
418
419   return result;
420 }
421
422 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink)
423 {
424         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
425
426         SEND_COMMAND (self, CONTROL_STOP);
427
428         return TRUE;
429 }
430
431 static gboolean gst_dvbaudiosink_unlock_stop (GstBaseSink * sink)
432 {
433         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
434         while (TRUE)
435         {
436                 gchar command;
437                 int res;
438                 
439                 READ_COMMAND (self, command, res);
440                 if (res < 0)
441                 {
442                 GST_LOG_OBJECT (self, "no more commands");
443                 /* no more commands */
444                 break;
445                 }
446         }
447         return TRUE;
448 }
449
450 static GstCaps *gst_dvbaudiosink_get_caps (GstBaseSink * basesink)
451 {
452         GstElementClass *element_class;
453         GstPadTemplate *pad_template;
454         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
455         GstCaps *in_caps, *caps;
456
457         element_class = GST_ELEMENT_GET_CLASS (self);
458         pad_template = gst_element_class_get_pad_template(element_class, "sink");
459         g_return_val_if_fail (pad_template != NULL, NULL);
460         
461         in_caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
462         in_caps = gst_caps_make_writable (in_caps);
463
464         GstStructure *s;
465         gint i;
466         
467         caps = gst_caps_new_empty ();
468
469         for (i = 0; i < gst_caps_get_size (in_caps); ++i)
470         {       
471                 s = gst_caps_get_structure (in_caps, i);
472                 if ( gst_structure_has_name (s, "audio/mpeg") )
473                 {
474                         GstStructure *mp1_struct = gst_structure_copy (s);
475
476                         gst_structure_set (mp1_struct, "mpegversion", G_TYPE_INT, 1, NULL);
477                         gst_structure_set (mp1_struct, "layer", GST_TYPE_INT_RANGE, 1, 2, NULL);
478                         gst_structure_set (mp1_struct, "rate", GST_TYPE_INT_RANGE, 0, 48000, NULL);
479                         gst_caps_append_structure (caps, mp1_struct);
480
481                         if ( self->priv->model >= DM800 )
482                         {
483                                 GstStructure *mp3_struct = gst_structure_copy (s);
484                                 gst_structure_set (mp3_struct, "mpegversion", G_TYPE_INT, 1, NULL);
485                                 gst_structure_set (mp3_struct, "layer", G_TYPE_INT, 3, NULL);
486                                 GValue value = { 0 };
487                                 GValue rate_value = { 0 };
488                                 g_value_init (&rate_value, GST_TYPE_LIST);
489                                 g_value_init (&value, G_TYPE_INT);
490                                 g_value_set_int (&value, 32000);
491                                 gst_value_list_append_value (&rate_value, &value);
492                                 g_value_set_int (&value, 44100);
493                                 gst_value_list_append_value (&rate_value, &value);
494                                 g_value_set_int (&value, 48000);
495                                 gst_value_list_append_value (&rate_value, &value);
496                                 gst_structure_set_value (mp3_struct, "rate", &rate_value);
497                                 g_value_unset (&value);
498                                 g_value_unset (&rate_value);
499                                 gst_caps_append_structure (caps, mp3_struct);
500         
501                                 GstStructure *mp2_struct = gst_structure_copy (s);
502                                 gst_structure_set (mp2_struct, "mpegversion", G_TYPE_INT, 2, NULL);
503                                 g_value_init (&rate_value, GST_TYPE_LIST);
504                                 g_value_init (&value, G_TYPE_INT);
505                                 gint rate_idx=0;
506                                 do {
507                                         g_value_set_int (&value, AdtsSamplingRates[rate_idx]);
508                                         gst_value_list_append_value (&rate_value, &value);
509                                         ++rate_idx;
510                                 } while (AdtsSamplingRates[rate_idx]);
511                                 gst_structure_set_value (mp2_struct, "rate", &rate_value);
512                                 g_value_unset (&value);
513                                 g_value_unset (&rate_value);
514                                 gst_caps_append_structure (caps, mp2_struct);
515         
516                                 GstStructure *mp4_struct = gst_structure_copy (mp2_struct);
517                                 gst_structure_set (mp4_struct, "mpegversion", G_TYPE_INT, 4, NULL);
518                                 gst_caps_append_structure (caps, mp4_struct);
519                         }
520                 }
521                 if ( gst_structure_has_name (s, "audio/x-ac3" ) || gst_structure_has_name (s, "audio/x-private1-ac3" ) )
522                 {
523                         GstStructure *ac3_struct = gst_structure_copy (s);
524                         gst_caps_append_structure (caps, ac3_struct);
525                 }
526                 if ( ( self->priv->model == DM8000 ) && ( gst_structure_has_name (s, "audio/x-dts" ) || gst_structure_has_name (s, "audio/x-private1-dts") ) )
527                 {
528                         GstStructure *dts_struct = gst_structure_copy (s);
529                         gst_caps_append_structure (caps, dts_struct);
530                 }
531         }
532
533         GST_DEBUG_OBJECT (self, "old caps: %s\nnew caps: %s\n", gst_caps_to_string(in_caps), gst_caps_to_string(caps));
534
535         gst_caps_unref (in_caps);
536
537         return caps;
538 }
539
540 static gboolean 
541 gst_dvbaudiosink_set_caps (GstBaseSink * basesink, GstCaps * caps)
542 {
543         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
544         GstStructure *structure = gst_caps_get_structure (caps, 0);
545         const char *type = gst_structure_get_name (structure);
546         int bypass = -1;
547
548         self->skip = 0;
549         if (!strcmp(type, "audio/mpeg")) {
550                 gint mpegversion;
551                 gst_structure_get_int (structure, "mpegversion", &mpegversion);
552                 switch (mpegversion) {
553                         case 1:
554                         {
555                                 gint layer;
556                                 gst_structure_get_int (structure, "layer", &layer);
557                                 if ( layer == 3 )
558                                         bypass = 0xA;
559                                 else
560                                         bypass = 1;
561                                 GST_INFO_OBJECT (self, "MIMETYPE %s version %d layer %d",type,mpegversion,layer);
562                                 break;
563                         }
564                         case 2:
565                         case 4:
566                         {
567                                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
568                                 GST_INFO_OBJECT (self, "MIMETYPE %s version %d (AAC)", type, mpegversion);
569                                 if (codec_data) {
570                                         guint8 *h = GST_BUFFER_DATA(gst_value_get_buffer (codec_data));
571                                         guint8 obj_type = ((h[0] & 0xC) >> 2) + 1;
572                                         guint8 rate_idx = ((h[0] & 0x3) << 1) | ((h[1] & 0x80) >> 7);
573                                         guint8 channels = (h[1] & 0x78) >> 3;
574 //                                      printf("have codec data -> obj_type = %d, rate_idx = %d, channels = %d\n",
575 //                                              obj_type, rate_idx, channels);
576                                         /* Sync point over a full byte */
577                                         self->aac_adts_header[0] = 0xFF;
578                                         /* Sync point continued over first 4 bits + static 4 bits
579                                          * (ID, layer, protection)*/
580                                         self->aac_adts_header[1] = 0xF1;
581                                         if (mpegversion == 2)
582                                                 self->aac_adts_header[1] |= 8;
583                                         /* Object type over first 2 bits */
584                                         self->aac_adts_header[2] = obj_type << 6;
585                                         /* rate index over next 4 bits */
586                                         self->aac_adts_header[2] |= rate_idx << 2;
587                                         /* channels over last 2 bits */
588                                         self->aac_adts_header[2] |= (channels & 0x4) >> 2;
589                                         /* channels continued over next 2 bits + 4 bits at zero */
590                                         self->aac_adts_header[3] = (channels & 0x3) << 6;
591                                         self->aac_adts_header_valid = TRUE;
592                                 }
593                                 else {
594                                         gint rate, channels, rate_idx=0, obj_type=1; // hardcoded yet.. hopefully this works every time ;)
595                                         GST_WARNING_OBJECT (self, "no codec data");
596                                         if (gst_structure_get_int (structure, "rate", &rate) && gst_structure_get_int (structure, "channels", &channels)) {
597                                                 do {
598                                                         if (AdtsSamplingRates[rate_idx] == rate)
599                                                                 break;
600                                                         ++rate_idx;
601                                                 } while (AdtsSamplingRates[rate_idx]);
602                                                 if (AdtsSamplingRates[rate_idx]) {
603                                                         GST_INFO_OBJECT (self, "mpegversion %d, channels %d, rate %d, rate_idx %d\n", mpegversion, channels, rate, rate_idx);
604                                                         /* Sync point over a full byte */
605                                                         self->aac_adts_header[0] = 0xFF;
606                                                         /* Sync point continued over first 4 bits + static 4 bits
607                                                          * (ID, layer, protection)*/
608                                                         self->aac_adts_header[1] = 0xF1;
609                                                         if (mpegversion == 2)
610                                                                 self->aac_adts_header[1] |= 8;
611                                                         /* Object type over first 2 bits */
612                                                         self->aac_adts_header[2] = obj_type << 6;
613                                                         /* rate index over next 4 bits */
614                                                         self->aac_adts_header[2] |= rate_idx << 2;
615                                                         /* channels over last 2 bits */
616                                                         self->aac_adts_header[2] |= (channels & 0x4) >> 2;
617                                                         /* channels continued over next 2 bits + 4 bits at zero */
618                                                         self->aac_adts_header[3] = (channels & 0x3) << 6;
619                                                         self->aac_adts_header_valid = TRUE;
620                                                 }
621                                         }
622                                 }
623                                 if (bypass == -1)
624                                         bypass = 0x0b;
625                                 break;
626                         }
627                         default:
628                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
629                                 break;
630                 }
631         }
632         else if (!strcmp(type, "audio/x-ac3") || !strcmp(type, "audio/ac3"))
633         {
634                 GST_INFO_OBJECT (self, "MIMETYPE %s",type);
635                 bypass = 0;
636         }
637         else if (!strcmp(type, "audio/x-private1-dts"))
638         {
639                 GST_INFO_OBJECT (self, "MIMETYPE %s (DVD Audio - 2 byte skipping)",type);
640                 bypass = 2;
641                 self->skip = 2;
642         }
643         else if (!strcmp(type, "audio/x-private1-ac3"))
644         {
645                 GST_INFO_OBJECT (self, "MIMETYPE %s (DVD Audio - 2 byte skipping)",type);
646                 bypass = 0;
647                 self->skip = 2;
648         } 
649         else if (!strcmp(type, "audio/x-dts") || !strcmp(type, "audio/dts"))
650         {
651                 GST_INFO_OBJECT (self, "MIMETYPE %s",type);
652                 bypass = 2;
653         } else
654         {
655                 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", type));
656                 return FALSE;
657         }
658
659         GST_INFO_OBJECT(self, "setting dvb mode 0x%02x\n", bypass);
660
661         if (ioctl(self->fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
662         {
663                 GST_ELEMENT_WARNING (self, STREAM, DECODE, (NULL), ("hardware decoder can't be set to bypass mode %i.", bypass));
664 //              return FALSE;
665         }
666         self->priv->bypass_set = TRUE;
667         return TRUE;
668 }
669
670 static gboolean
671 gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event)
672 {
673         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
674         GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
675
676         switch (GST_EVENT_TYPE (event)) {
677         case GST_EVENT_FLUSH_START:
678                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
679                 break;
680         case GST_EVENT_FLUSH_STOP:
681                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
682                 break;
683         case GST_EVENT_EOS:
684         {
685                 struct pollfd pfd[2];
686                 int retval;
687                 pfd[0].fd = READ_SOCKET(self);
688                 pfd[0].events = POLLIN;
689 #if 0
690                         /* needs driver support */
691                 pfd[1].fd = self->fd;
692                 pfd[1].events = POLLHUP;
693
694                 do {
695                         GST_DEBUG_OBJECT (self, "going into poll to wait for EOS");
696                         retval = poll(pfd, 2, -1);
697                 } while ((retval == -1 && errno == EINTR));
698                 
699                 if (pfd[0].revents & POLLIN) /* flush */
700                         break;
701                 GST_DEBUG_OBJECT (self, "EOS wait ended because of buffer empty. now waiting for PTS %llx", self->pts_eos);
702 #else
703                 if (self->prev_data) {
704                         int i=0;
705                         for (; i < 3; ++i)  // write the last frame three times more to fill the buffer...
706                                 gst_dvbaudiosink_render (sink, self->prev_data);
707                 }
708
709                 do {
710                         unsigned long long cur;
711
712                         ioctl(self->fd, AUDIO_GET_PTS, &cur);
713
714                         long long diff = self->pts_eos - cur;
715
716                         GST_DEBUG_OBJECT (self, "at %llx last %llx (diff %lld)\n", cur, self->pts_eos, diff);
717
718                         if ( diff <= 100 )
719                                 break;
720
721                         retval = poll(pfd, 1, 500);
722
723                                 /* check for flush */
724                         if (pfd[0].revents & POLLIN)
725                                 break;
726                 } while (1);
727 #endif
728                 break;
729         }
730         case GST_EVENT_NEWSEGMENT:{
731                 GstFormat fmt;
732                 gboolean update;
733                 gdouble rate, applied_rate;
734                 gint64 cur, stop, time;
735                 int skip = 0, repeat = 0, ret;
736                 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &fmt, &cur, &stop, &time);
737                 GST_LOG_OBJECT (self, "GST_EVENT_NEWSEGMENT rate=%f applied_rate=%f\n", rate, applied_rate);
738                 int video_fd = open("/dev/dvb/adapter0/video0", O_RDWR);
739
740                 if (fmt == GST_FORMAT_TIME)
741                 {
742                         if ( rate > 1 )
743                                 skip = (int) rate;
744                         else if ( rate < 1 )
745                                 repeat = 1.0/rate;
746
747                         ret = ioctl(video_fd, VIDEO_SLOWMOTION, repeat);
748                         ret = ioctl(video_fd, VIDEO_FAST_FORWARD, skip);
749
750 //                      gst_segment_set_newsegment_full (&dec->segment, update, rate, applied_rate, dformat, cur, stop, time);
751
752                 }
753                 close(video_fd);
754                 break;
755         }
756
757         default:
758                 break;
759         }
760         return TRUE;
761 }
762
763 static GstFlowReturn
764 gst_dvbaudiosink_render (GstBaseSink * sink, GstBuffer * buffer)
765 {
766         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
767         unsigned char pes_header[64];
768         int skip = self->skip;
769         unsigned int size = GST_BUFFER_SIZE (buffer) - skip;
770         unsigned char *data = GST_BUFFER_DATA (buffer) + skip;
771         gint retval;
772         size_t pes_header_size;
773         struct pollfd pfd[2];
774
775 //      int i=0;
776 //      for (;i < (size > 0x1F ? 0x1F : size); ++i)
777 //              printf("%02x ", data[i]);
778 //      printf("%d bytes\n", size);
779 //      printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
780
781         if ( !self->priv->bypass_set )
782         {
783                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("hardware decoder not setup (no caps in pipeline?)"));
784                 return GST_FLOW_ERROR;
785         }
786
787         pfd[0].fd = READ_SOCKET(self);
788         pfd[0].events = POLLIN;
789         pfd[1].fd = self->fd;
790         pfd[1].events = POLLOUT;
791
792         do {
793                 GST_LOG_OBJECT (self, "going into poll, have %d bytes to write", size);
794                 retval = poll(pfd, 2, -1);
795         } while ((retval == -1 && errno == EINTR));
796
797         if (retval == -1)
798                 goto poll_error;
799
800         if (pfd[0].revents & POLLIN) {
801                 /* read all stop commands */
802                 while (TRUE) {
803                         gchar command;
804                         int res;
805
806                         READ_COMMAND (self, command, res);
807                         if (res < 0) {
808                                 GST_LOG_OBJECT (self, "no more commands");
809                                 /* no more commands */
810                                 break;
811                         }
812                 }
813                 goto stopped;
814         }
815
816         if (self->fd < 0)
817                 return GST_FLOW_OK;
818
819         pes_header[0] = 0;
820         pes_header[1] = 0;
821         pes_header[2] = 1;
822         pes_header[3] = 0xC0;
823
824         if (self->aac_adts_header_valid)
825                 size += 7;
826
827                 /* do we have a timestamp? */
828         if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE)
829         {
830                 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
831
832                 self->pts_eos = pts;
833
834                 pes_header[4] = (size + 8) >> 8;
835                 pes_header[5] = (size + 8) & 0xFF;
836                 
837                 pes_header[6] = 0x80;
838                 pes_header[7] = 0x80;
839                 
840                 pes_header[8] = 5;
841                 
842                 pes_header[9]  = 0x21 | ((pts >> 29) & 0xE);
843                 pes_header[10] = pts >> 22;
844                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
845                 pes_header[12] = pts >> 7;
846                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
847                 pes_header_size = 14;
848         } else
849         {
850                 pes_header[4] = (size + 3) >> 8;
851                 pes_header[5] = (size + 3) & 0xFF;
852                 pes_header[6] = 0x80;
853                 pes_header[7] = 0x00;
854                 pes_header[8] = 0;
855                 pes_header_size = 9;
856         }
857
858         if (self->aac_adts_header_valid) {
859                 self->aac_adts_header[3] &= 0xC0;
860                 /* frame size over last 2 bits */
861                 self->aac_adts_header[3] |= (size & 0x1800) >> 11;
862                 /* frame size continued over full byte */
863                 self->aac_adts_header[4] = (size & 0x1FF8) >> 3;
864                 /* frame size continued first 3 bits */
865                 self->aac_adts_header[5] = (size & 7) << 5;
866                 /* buffer fullness (0x7FF for VBR) over 5 last bits */
867                 self->aac_adts_header[5] |= 0x1F;
868                 /* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for
869                  * number of raw data blocks */
870                 self->aac_adts_header[6] = 0xFC;
871                 memcpy(pes_header + pes_header_size, self->aac_adts_header, 7);
872                 pes_header_size += 7;
873         }
874
875         write(self->fd, pes_header, pes_header_size);
876         write(self->fd, data, GST_BUFFER_SIZE (buffer) - skip);
877
878         gst_buffer_ref(buffer);
879
880         if (self->prev_data)
881                 gst_buffer_unref(self->prev_data);
882
883         self->prev_data = buffer;
884
885         return GST_FLOW_OK;
886 poll_error:
887         {
888                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
889                                 ("poll on file descriptor: %s.", g_strerror (errno)));
890                 GST_WARNING_OBJECT (self, "Error during poll");
891                 return GST_FLOW_ERROR;
892         }
893 stopped:
894         {
895                 GST_WARNING_OBJECT (self, "Select stopped");
896                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
897                 return GST_FLOW_WRONG_STATE;
898         }
899 }
900
901 static gboolean
902 gst_dvbaudiosink_start (GstBaseSink * basesink)
903 {
904         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
905         gint control_sock[2];
906         int val = 1;
907         self->fd = open("/dev/dvb/adapter0/audio0", O_RDWR);
908 //      self->fd = open("/dump.pes", O_RDWR|O_CREAT, 0555);
909
910         if (socketpair(PF_UNIX, SOCK_STREAM, 0, control_sock) < 0) {
911                 perror("socketpair");
912                 goto socket_pair;
913         }
914
915         if (setsockopt(control_sock[0], SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) {
916                 perror("setsockopt");
917                 goto socket_pair;
918         }
919
920         if (setsockopt(control_sock[1], SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) {
921                 perror("setsockopt");
922                 goto socket_pair;
923         }
924
925         READ_SOCKET (self) = control_sock[0];
926         WRITE_SOCKET (self) = control_sock[1];
927
928         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
929         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
930
931         if (self->fd)
932         {
933                 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY);
934                 ioctl(self->fd, AUDIO_PLAY);
935 //              ioctl(self->fd, AUDIO_SET_BYPASS_MODE, 0);
936         }
937         return TRUE;
938         /* ERRORS */
939 socket_pair:
940         {
941                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
942                                 GST_ERROR_SYSTEM);
943                 return FALSE;
944         }
945 }
946
947 static gboolean
948 gst_dvbaudiosink_stop (GstBaseSink * basesink)
949 {
950         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
951         if (self->fd >= 0)
952         {
953                 ioctl(self->fd, AUDIO_STOP);
954                 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX);
955
956                 int video_fd = open("/dev/dvb/adapter0/video0", O_RDWR);
957                 if ( video_fd > 0 )
958                 {
959                         ioctl(video_fd, VIDEO_SLOWMOTION, 0);
960                         ioctl(video_fd, VIDEO_FAST_FORWARD, 0);
961                         close (video_fd);
962                 }
963                 close(self->fd);
964         }
965
966         if (self->prev_data)
967                 gst_buffer_unref(self->prev_data);
968
969         return TRUE;
970 }
971
972 /* entry point to initialize the plug-in
973  * initialize the plug-in itself
974  * register the element factories and pad templates
975  * register the features
976  *
977  * exchange the string 'plugin' with your elemnt name
978  */
979 static gboolean
980 plugin_init (GstPlugin *plugin)
981 {
982         return gst_element_register (plugin, "dvbaudiosink",
983                                                  GST_RANK_PRIMARY,
984                                                  GST_TYPE_DVBAUDIOSINK);
985 }
986
987 /* this is the structure that gstreamer looks for to register plugins
988  *
989  * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
990  * description
991  */
992 GST_PLUGIN_DEFINE (
993         GST_VERSION_MAJOR,
994         GST_VERSION_MINOR,
995         "dvb_audio_out",
996         "DVB Audio Output",
997         plugin_init,
998         VERSION,
999         "LGPL",
1000         "GStreamer",
1001         "http://gstreamer.net/"
1002 )