small cleanup
[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         GstElementClass *gelement_class = GST_ELEMENT_CLASS (klass);
198
199         g_type_class_add_private (klass, sizeof (GstDVBAudioSinkPrivate));
200
201         gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_set_property);
202         gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_get_property);
203         gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_dispose);
204
205         gstbasesink_class->get_times = NULL;
206         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_start);
207         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_stop);
208         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_render);
209         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_event);
210         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_unlock);
211         gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR ( gst_dvbaudiosink_unlock_stop);
212         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_set_caps);
213         gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_get_caps);
214
215         gelement_class->provide_clock = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_provide_clock);
216         gelement_class->query = GST_DEBUG_FUNCPTR(gst_dvbaudiosink_query);
217
218         g_object_class_install_property (gobject_class, ARG_SILENT, g_param_spec_boolean
219                 ("silent", "Silent", "Produce verbose output ?", FALSE, G_PARAM_READWRITE));
220         g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK, g_param_spec_boolean
221                 ("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));
222 }
223
224 /* initialize the new element
225  * instantiate pads and add them to element
226  * set functions
227  * initialize structure
228  */
229 static void
230 gst_dvbaudiosink_init (GstDVBAudioSink *klass, GstDVBAudioSinkClass * gclass)
231 {
232         klass->priv = GST_DVBAUDIOSINK_GET_PRIVATE (klass);
233         klass->priv->bypass_set = FALSE;
234         klass->provide_clock = DEFAULT_PROVIDE_CLOCK;
235         klass->silent = FALSE;
236         klass->aac_adts_header_valid = FALSE;
237
238         GST_BASE_SINK (klass)->sync = TRUE;
239
240         klass->provided_clock = gst_audio_clock_new ("GstDVBAudioSinkClock", (GstAudioClockGetTimeFunc) gst_dvbaudiosink_get_time, klass);
241
242         klass->priv->model = DMLEGACY;
243         int fd = open("/proc/stb/info/model", O_RDONLY);
244         if ( fd > 0 )
245         {
246                 gchar string[8] = { 0, };
247                 ssize_t rd = read(fd, string, 7);
248                 if ( rd >= 5 )
249                 {
250                         if ( !strncasecmp(string, "DM7025", 6) )
251                                 klass->priv->model = DM7025;
252                         else if ( !strncasecmp(string, "DM8000", 6) )
253                                 klass->priv->model = DM8000;
254                         else if ( !strncasecmp(string, "DM800", 5) )
255                                 klass->priv->model = DM800;
256                         else if ( !strncasecmp(string, "DM500HD", 7) )
257                                 klass->priv->model = DM500HD;
258                 }
259                 close(fd);
260                 GST_INFO_OBJECT (klass, "found hardware model %s (%i)",string,klass->priv->model);
261         }
262 }
263
264 static void gst_dvbaudiosink_dispose (GObject * object)
265 {
266         GstDVBAudioSink *self;
267         
268         self = GST_DVBAUDIOSINK (object);
269         
270         if (self->provided_clock)
271                 gst_object_unref (self->provided_clock);
272         self->provided_clock = NULL;
273
274         close (READ_SOCKET (self));
275         close (WRITE_SOCKET (self));
276         READ_SOCKET (self) = -1;
277         WRITE_SOCKET (self) = -1;
278
279         G_OBJECT_CLASS (parent_class)->dispose (object);
280 }
281
282 static GstClock *
283 gst_dvbaudiosink_provide_clock (GstElement * element)
284 {
285   GstClock *clock;
286   GstDVBAudioSink *self = GST_DVBAUDIOSINK (element);
287
288   GST_OBJECT_LOCK (self);
289   if (!self->provide_clock)
290     goto clock_disabled;
291
292   clock = GST_CLOCK_CAST (gst_object_ref (self->provided_clock));
293   GST_OBJECT_UNLOCK (self);
294
295   return clock;
296
297   /* ERRORS */
298 clock_disabled:
299   {
300     GST_DEBUG_OBJECT (self, "clock provide disabled");
301     GST_OBJECT_UNLOCK (self);
302     return NULL;
303   }
304 }
305
306 static void
307 gst_dvbaudiosink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
308 {
309         GstDVBAudioSink *self;
310
311         g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
312         self = GST_DVBAUDIOSINK (object);
313
314         switch (prop_id)
315         {
316         case ARG_SILENT:
317                 self->silent = g_value_get_boolean (value);
318                 break;
319         case PROP_PROVIDE_CLOCK:
320                 gst_dvbaudiosink_set_provide_clock (self, g_value_get_boolean (value));
321                 break;
322         default:
323                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324                 break;
325         }
326 }
327
328 static void
329 gst_dvbaudiosink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
330 {
331         GstDVBAudioSink *self;
332
333         g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
334         self = GST_DVBAUDIOSINK (object);
335
336         switch (prop_id) {
337         case ARG_SILENT:
338                 g_value_set_boolean (value, self->silent);
339                 break;
340         case PROP_PROVIDE_CLOCK:
341                 g_value_set_boolean (value, gst_dvbaudiosink_get_provide_clock (self));
342                 break;
343         default:
344                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345                 break;
346         }
347 }
348
349 static gboolean
350 gst_dvbaudiosink_query (GstElement * element, GstQuery * query)
351 {
352         GstDVBAudioSink *self = GST_DVBAUDIOSINK (element);
353
354         switch (GST_QUERY_TYPE (query)) {
355         case GST_QUERY_POSITION:
356         {
357                 gint64 cur = 0, res = 0;
358                 static gint64 last_pos = 0;
359                 GstFormat format;
360
361                 gst_query_parse_position (query, &format, NULL);
362
363                 if (format != GST_FORMAT_TIME)
364                         goto query_default;
365
366                 ioctl(self->fd, AUDIO_GET_PTS, &cur);
367
368                 /* workaround until driver fixed */
369                 if (cur)
370                         last_pos = cur;
371                 else
372                         cur = last_pos;
373
374                 res = cur *11111;
375
376                 gst_query_set_position (query, format, res);
377
378                 GST_LOG_OBJECT (self, "GST_QUERY_POSITION pts=%lld: %" G_GUINT64_FORMAT ", time: %" GST_TIME_FORMAT, cur, GST_TIME_ARGS (res));
379                 return TRUE;
380         }
381         default:
382 query_default:
383                 return GST_ELEMENT_CLASS (parent_class)->query (element, query);
384         }
385 }
386
387 static GstClockTime
388 gst_dvbaudiosink_get_time (GstClock * clock, GstDVBAudioSink * sink)
389 {
390         GstClockTime result;
391         
392         gint64 cur = 0;
393         ioctl(sink->fd, AUDIO_GET_PTS, &cur);
394
395         result = cur * 11111;
396
397         GST_LOG_OBJECT (sink, "get_time pts=%lld: %" G_GUINT64_FORMAT ", time: %" GST_TIME_FORMAT, cur, GST_TIME_ARGS (result));
398
399         return result;
400 }
401
402 void
403 gst_dvbaudiosink_set_provide_clock (GstDVBAudioSink * sink, gboolean provide)
404 {
405   g_return_if_fail (GST_IS_DVBAUDIOSINK (sink));
406
407   GST_OBJECT_LOCK (sink);
408   sink->provide_clock = provide;
409   GST_OBJECT_UNLOCK (sink);
410 }
411
412 gboolean
413 gst_dvbaudiosink_get_provide_clock (GstDVBAudioSink * sink)
414 {
415   gboolean result;
416
417   g_return_val_if_fail (GST_IS_DVBAUDIOSINK (sink), FALSE);
418
419   GST_OBJECT_LOCK (sink);
420   result = sink->provide_clock;
421   GST_OBJECT_UNLOCK (sink);
422
423   return result;
424 }
425
426 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink)
427 {
428         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
429
430         SEND_COMMAND (self, CONTROL_STOP);
431
432         return TRUE;
433 }
434
435 static gboolean gst_dvbaudiosink_unlock_stop (GstBaseSink * sink)
436 {
437         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
438         while (TRUE)
439         {
440                 gchar command;
441                 int res;
442                 
443                 READ_COMMAND (self, command, res);
444                 if (res < 0)
445                 {
446                 GST_LOG_OBJECT (self, "no more commands");
447                 /* no more commands */
448                 break;
449                 }
450         }
451         return TRUE;
452 }
453
454 static GstCaps *gst_dvbaudiosink_get_caps (GstBaseSink * basesink)
455 {
456         GstElementClass *element_class;
457         GstPadTemplate *pad_template;
458         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
459         GstCaps *in_caps, *caps;
460
461         element_class = GST_ELEMENT_GET_CLASS (self);
462         pad_template = gst_element_class_get_pad_template(element_class, "sink");
463         g_return_val_if_fail (pad_template != NULL, NULL);
464         
465         in_caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
466         in_caps = gst_caps_make_writable (in_caps);
467
468         GstStructure *s;
469         gint i;
470         
471         caps = gst_caps_new_empty ();
472
473         for (i = 0; i < gst_caps_get_size (in_caps); ++i)
474         {       
475                 s = gst_caps_get_structure (in_caps, i);
476                 if ( gst_structure_has_name (s, "audio/mpeg") )
477                 {
478                         GstStructure *mp1_struct = gst_structure_copy (s);
479
480                         gst_structure_set (mp1_struct, "mpegversion", G_TYPE_INT, 1, NULL);
481                         gst_structure_set (mp1_struct, "layer", GST_TYPE_INT_RANGE, 1, 2, NULL);
482                         gst_structure_set (mp1_struct, "rate", GST_TYPE_INT_RANGE, 0, 48000, NULL);
483                         gst_caps_append_structure (caps, mp1_struct);
484
485                         if ( self->priv->model >= DM800 )
486                         {
487                                 GstStructure *mp3_struct = gst_structure_copy (s);
488                                 gst_structure_set (mp3_struct, "mpegversion", G_TYPE_INT, 1, NULL);
489                                 gst_structure_set (mp3_struct, "layer", G_TYPE_INT, 3, NULL);
490                                 GValue value = { 0 };
491                                 GValue rate_value = { 0 };
492                                 g_value_init (&rate_value, GST_TYPE_LIST);
493                                 g_value_init (&value, G_TYPE_INT);
494                                 gint rate_idx=0;
495                                 do {
496                                         int rate = AdtsSamplingRates[rate_idx];
497                                         ++rate_idx;
498                                         if ( rate > 48000 )
499                                                 continue;
500                                         else if ( rate < 8000 )
501                                                 break;
502                                         g_value_set_int (&value, rate);
503                                         gst_value_list_append_value (&rate_value, &value);
504                                 } while (AdtsSamplingRates[rate_idx]);
505                                 gst_structure_set_value (mp3_struct, "rate", &rate_value);
506                                 g_value_unset (&value);
507                                 g_value_unset (&rate_value);
508                                 gst_caps_append_structure (caps, mp3_struct);
509         
510                                 GstStructure *mp2_struct = gst_structure_copy (s);
511                                 gst_structure_set (mp2_struct, "mpegversion", G_TYPE_INT, 2, NULL);
512                                 g_value_init (&rate_value, GST_TYPE_LIST);
513                                 g_value_init (&value, G_TYPE_INT);
514                                 rate_idx=0;
515                                 do {
516                                         g_value_set_int (&value, AdtsSamplingRates[rate_idx]);
517                                         gst_value_list_append_value (&rate_value, &value);
518                                         ++rate_idx;
519                                 } while (AdtsSamplingRates[rate_idx]);
520                                 gst_structure_set_value (mp2_struct, "rate", &rate_value);
521                                 g_value_unset (&value);
522                                 g_value_unset (&rate_value);
523                                 gst_caps_append_structure (caps, mp2_struct);
524         
525                                 GstStructure *mp4_struct = gst_structure_copy (mp2_struct);
526                                 gst_structure_set (mp4_struct, "mpegversion", G_TYPE_INT, 4, NULL);
527                                 gst_caps_append_structure (caps, mp4_struct);
528                         }
529                 }
530                 if ( gst_structure_has_name (s, "audio/x-ac3" ) || gst_structure_has_name (s, "audio/x-private1-ac3" ) )
531                 {
532                         GstStructure *ac3_struct = gst_structure_copy (s);
533                         gst_caps_append_structure (caps, ac3_struct);
534                 }
535                 if ( ( self->priv->model == DM8000 ) && ( gst_structure_has_name (s, "audio/x-dts" ) || gst_structure_has_name (s, "audio/x-private1-dts") ) )
536                 {
537                         GstStructure *dts_struct = gst_structure_copy (s);
538                         gst_caps_append_structure (caps, dts_struct);
539                 }
540         }
541
542         GST_DEBUG_OBJECT (self, "old caps: %s\nnew caps: %s\n", gst_caps_to_string(in_caps), gst_caps_to_string(caps));
543
544         gst_caps_unref (in_caps);
545
546         return caps;
547 }
548
549 static gboolean 
550 gst_dvbaudiosink_set_caps (GstBaseSink * basesink, GstCaps * caps)
551 {
552         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
553         GstStructure *structure = gst_caps_get_structure (caps, 0);
554         const char *type = gst_structure_get_name (structure);
555         int bypass = -1;
556
557         self->skip = 0;
558         self->is_dts = 0;
559         if (!strcmp(type, "audio/mpeg")) {
560                 gint mpegversion;
561                 gst_structure_get_int (structure, "mpegversion", &mpegversion);
562                 switch (mpegversion) {
563                         case 1:
564                         {
565                                 gint layer;
566                                 gst_structure_get_int (structure, "layer", &layer);
567                                 if ( layer == 3 )
568                                         bypass = 0xA;
569                                 else
570                                         bypass = 1;
571                                 GST_INFO_OBJECT (self, "MIMETYPE %s version %d layer %d",type,mpegversion,layer);
572                                 break;
573                         }
574                         case 2:
575                         case 4:
576                         {
577                                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
578                                 GST_INFO_OBJECT (self, "MIMETYPE %s version %d (AAC)", type, mpegversion);
579                                 if (codec_data) {
580                                         guint8 *h = GST_BUFFER_DATA(gst_value_get_buffer (codec_data));
581                                         guint8 obj_type = ((h[0] & 0xC) >> 2) + 1;
582                                         guint8 rate_idx = ((h[0] & 0x3) << 1) | ((h[1] & 0x80) >> 7);
583                                         guint8 channels = (h[1] & 0x78) >> 3;
584                                         GST_INFO_OBJECT (self, "have codec data -> obj_type = %d, rate_idx = %d, channels = %d\n",
585                                                 obj_type, rate_idx, channels);
586                                         /* Sync point over a full byte */
587                                         self->aac_adts_header[0] = 0xFF;
588                                         /* Sync point continued over first 4 bits + static 4 bits
589                                          * (ID, layer, protection)*/
590                                         self->aac_adts_header[1] = 0xF1;
591                                         if (mpegversion == 2)
592                                                 self->aac_adts_header[1] |= 8;
593                                         /* Object type over first 2 bits */
594                                         self->aac_adts_header[2] = obj_type << 6;
595                                         /* rate index over next 4 bits */
596                                         self->aac_adts_header[2] |= rate_idx << 2;
597                                         /* channels over last 2 bits */
598                                         self->aac_adts_header[2] |= (channels & 0x4) >> 2;
599                                         /* channels continued over next 2 bits + 4 bits at zero */
600                                         self->aac_adts_header[3] = (channels & 0x3) << 6;
601                                         self->aac_adts_header_valid = TRUE;
602                                 }
603                                 else {
604                                         gint rate, channels, rate_idx=0, obj_type=1; // hardcoded yet.. hopefully this works every time ;)
605                                         GST_INFO_OBJECT (self, "no codec data");
606                                         if (gst_structure_get_int (structure, "rate", &rate) && gst_structure_get_int (structure, "channels", &channels)) {
607                                                 do {
608                                                         if (AdtsSamplingRates[rate_idx] == rate)
609                                                                 break;
610                                                         ++rate_idx;
611                                                 } while (AdtsSamplingRates[rate_idx]);
612                                                 if (AdtsSamplingRates[rate_idx]) {
613                                                         GST_INFO_OBJECT (self, "mpegversion %d, channels %d, rate %d, rate_idx %d\n", mpegversion, channels, rate, rate_idx);
614                                                         /* Sync point over a full byte */
615                                                         self->aac_adts_header[0] = 0xFF;
616                                                         /* Sync point continued over first 4 bits + static 4 bits
617                                                          * (ID, layer, protection)*/
618                                                         self->aac_adts_header[1] = 0xF1;
619                                                         if (mpegversion == 2)
620                                                                 self->aac_adts_header[1] |= 8;
621                                                         /* Object type over first 2 bits */
622                                                         self->aac_adts_header[2] = obj_type << 6;
623                                                         /* rate index over next 4 bits */
624                                                         self->aac_adts_header[2] |= rate_idx << 2;
625                                                         /* channels over last 2 bits */
626                                                         self->aac_adts_header[2] |= (channels & 0x4) >> 2;
627                                                         /* channels continued over next 2 bits + 4 bits at zero */
628                                                         self->aac_adts_header[3] = (channels & 0x3) << 6;
629                                                         self->aac_adts_header_valid = TRUE;
630                                                 }
631                                         }
632                                 }
633                                 if (bypass == -1)
634                                         bypass = 0x0b;
635                                 break;
636                         }
637                         default:
638                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
639                                 break;
640                 }
641         }
642         else if (!strcmp(type, "audio/x-ac3") || !strcmp(type, "audio/ac3"))
643         {
644                 GST_INFO_OBJECT (self, "MIMETYPE %s",type);
645                 bypass = 0;
646         }
647         else if (!strcmp(type, "audio/x-private1-dts"))
648         {
649                 GST_INFO_OBJECT (self, "MIMETYPE %s (DVD Audio - 2 byte skipping)",type);
650                 bypass = 2;
651                 self->skip = 2;
652                 self->is_dts = 1;
653         }
654         else if (!strcmp(type, "audio/x-private1-ac3"))
655         {
656                 GST_INFO_OBJECT (self, "MIMETYPE %s (DVD Audio - 2 byte skipping)",type);
657                 bypass = 0;
658                 self->skip = 2;
659         } 
660         else if (!strcmp(type, "audio/x-dts") || !strcmp(type, "audio/dts"))
661         {
662                 GST_INFO_OBJECT (self, "MIMETYPE %s",type);
663                 bypass = 2;
664                 self->is_dts = 1;
665         } else
666         {
667                 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", type));
668                 return FALSE;
669         }
670
671         GST_INFO_OBJECT(self, "setting dvb mode 0x%02x\n", bypass);
672
673         if (ioctl(self->fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
674         {
675                 if (self->is_dts) {
676                         GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("hardware decoder can't be set to bypass mode type %s", type));
677                         return FALSE;
678                 }
679                 GST_ELEMENT_WARNING (self, STREAM, DECODE, (NULL), ("hardware decoder can't be set to bypass mode %i.", bypass));
680 //              return FALSE;
681         }
682         self->priv->bypass_set = TRUE;
683         return TRUE;
684 }
685
686 static gboolean
687 gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event)
688 {
689         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
690         GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
691
692         switch (GST_EVENT_TYPE (event)) {
693         case GST_EVENT_FLUSH_START:
694                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
695                 break;
696         case GST_EVENT_FLUSH_STOP:
697                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
698                 break;
699         case GST_EVENT_EOS:
700         {
701                 struct pollfd pfd[2];
702                 int retval;
703                 pfd[0].fd = READ_SOCKET(self);
704                 pfd[0].events = POLLIN;
705 #if 0
706                         /* needs driver support */
707                 pfd[1].fd = self->fd;
708                 pfd[1].events = POLLHUP;
709
710                 do {
711                         GST_DEBUG_OBJECT (self, "going into poll to wait for EOS");
712                         retval = poll(pfd, 2, -1);
713                 } while ((retval == -1 && errno == EINTR));
714                 
715                 if (pfd[0].revents & POLLIN) /* flush */
716                         break;
717                 GST_DEBUG_OBJECT (self, "EOS wait ended because of buffer empty. now waiting for PTS %llx", self->pts_eos);
718 #else
719                 if (self->prev_data) {
720                         int i=0;
721                         for (; i < 3; ++i)  // write the last frame three times more to fill the buffer...
722                                 gst_dvbaudiosink_render (sink, self->prev_data);
723                 }
724
725                 do {
726                         unsigned long long cur;
727
728                         ioctl(self->fd, AUDIO_GET_PTS, &cur);
729
730                         long long diff = self->pts_eos - cur;
731
732                         GST_DEBUG_OBJECT (self, "at %llx last %llx (diff %lld)\n", cur, self->pts_eos, diff);
733
734                         if ( diff <= 100 )
735                                 break;
736
737                         retval = poll(pfd, 1, 500);
738
739                                 /* check for flush */
740                         if (pfd[0].revents & POLLIN)
741                                 break;
742                 } while (1);
743 #endif
744                 break;
745         }
746         case GST_EVENT_NEWSEGMENT:{
747                 GstFormat fmt;
748                 gboolean update;
749                 gdouble rate, applied_rate;
750                 gint64 cur, stop, time;
751                 int skip = 0, repeat = 0, ret;
752                 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &fmt, &cur, &stop, &time);
753                 GST_LOG_OBJECT (self, "GST_EVENT_NEWSEGMENT rate=%f applied_rate=%f\n", rate, applied_rate);
754                 int video_fd = open("/dev/dvb/adapter0/video0", O_RDWR);
755
756                 if (fmt == GST_FORMAT_TIME)
757                 {
758                         if ( rate > 1 )
759                                 skip = (int) rate;
760                         else if ( rate < 1 )
761                                 repeat = 1.0/rate;
762
763                         ret = ioctl(video_fd, VIDEO_SLOWMOTION, repeat);
764                         ret = ioctl(video_fd, VIDEO_FAST_FORWARD, skip);
765
766 //                      gst_segment_set_newsegment_full (&dec->segment, update, rate, applied_rate, dformat, cur, stop, time);
767
768                 }
769                 close(video_fd);
770                 break;
771         }
772
773         default:
774                 break;
775         }
776         return TRUE;
777 }
778
779 static GstFlowReturn
780 gst_dvbaudiosink_render (GstBaseSink * sink, GstBuffer * buffer)
781 {
782         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
783         unsigned char pes_header[64];
784         int skip = self->skip;
785         unsigned int size = GST_BUFFER_SIZE (buffer) - skip;
786         unsigned char *data = GST_BUFFER_DATA (buffer) + skip;
787         gint retval;
788         size_t pes_header_size;
789         struct pollfd pfd[2];
790
791 //      int i=0;
792 //      for (;i < (size > 0x1F ? 0x1F : size); ++i)
793 //              printf("%02x ", data[i]);
794 //      printf("%d bytes\n", size);
795 //      printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
796
797         if ( !self->priv->bypass_set )
798         {
799                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("hardware decoder not setup (no caps in pipeline?)"));
800                 return GST_FLOW_ERROR;
801         }
802
803         pfd[0].fd = READ_SOCKET(self);
804         pfd[0].events = POLLIN;
805         pfd[1].fd = self->fd;
806         pfd[1].events = POLLOUT;
807
808         do {
809                 GST_LOG_OBJECT (self, "going into poll, have %d bytes to write", size);
810                 retval = poll(pfd, 2, -1);
811         } while ((retval == -1 && errno == EINTR));
812
813         if (retval == -1)
814                 goto poll_error;
815
816         if (pfd[0].revents & POLLIN) {
817                 /* read all stop commands */
818                 while (TRUE) {
819                         gchar command;
820                         int res;
821
822                         READ_COMMAND (self, command, res);
823                         if (res < 0) {
824                                 GST_LOG_OBJECT (self, "no more commands");
825                                 /* no more commands */
826                                 break;
827                         }
828                 }
829                 goto stopped;
830         }
831
832         if (self->fd < 0)
833                 return GST_FLOW_OK;
834
835         pes_header[0] = 0;
836         pes_header[1] = 0;
837         pes_header[2] = 1;
838         pes_header[3] = 0xC0;
839
840         if (self->is_dts) {
841                 int pos=0;
842                 while((pos+3) < size) {
843                         if (!strcmp((char*)(data+pos), "\x64\x58\x20\x25")) {  // is DTS-HD ?
844                                 skip += (size - pos);
845                                 size = pos;
846                                 break;
847                         }
848                         ++pos;
849                 }
850         }
851
852         if (self->aac_adts_header_valid)
853                 size += 7;
854
855                 /* do we have a timestamp? */
856         if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE)
857         {
858                 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
859
860                 self->pts_eos = pts;
861
862                 pes_header[4] = (size + 8) >> 8;
863                 pes_header[5] = (size + 8) & 0xFF;
864                 
865                 pes_header[6] = 0x80;
866                 pes_header[7] = 0x80;
867                 
868                 pes_header[8] = 5;
869                 
870                 pes_header[9]  = 0x21 | ((pts >> 29) & 0xE);
871                 pes_header[10] = pts >> 22;
872                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
873                 pes_header[12] = pts >> 7;
874                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
875                 pes_header_size = 14;
876         } else
877         {
878                 pes_header[4] = (size + 3) >> 8;
879                 pes_header[5] = (size + 3) & 0xFF;
880                 pes_header[6] = 0x80;
881                 pes_header[7] = 0x00;
882                 pes_header[8] = 0;
883                 pes_header_size = 9;
884         }
885
886         if (self->aac_adts_header_valid) {
887                 self->aac_adts_header[3] &= 0xC0;
888                 /* frame size over last 2 bits */
889                 self->aac_adts_header[3] |= (size & 0x1800) >> 11;
890                 /* frame size continued over full byte */
891                 self->aac_adts_header[4] = (size & 0x1FF8) >> 3;
892                 /* frame size continued first 3 bits */
893                 self->aac_adts_header[5] = (size & 7) << 5;
894                 /* buffer fullness (0x7FF for VBR) over 5 last bits */
895                 self->aac_adts_header[5] |= 0x1F;
896                 /* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for
897                  * number of raw data blocks */
898                 self->aac_adts_header[6] = 0xFC;
899                 memcpy(pes_header + pes_header_size, self->aac_adts_header, 7);
900                 pes_header_size += 7;
901         }
902
903         write(self->fd, pes_header, pes_header_size);
904         write(self->fd, data, GST_BUFFER_SIZE (buffer) - skip);
905
906         gst_buffer_ref(buffer);
907
908         if (self->prev_data)
909                 gst_buffer_unref(self->prev_data);
910
911         self->prev_data = buffer;
912
913         return GST_FLOW_OK;
914 poll_error:
915         {
916                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
917                                 ("poll on file descriptor: %s.", g_strerror (errno)));
918                 GST_WARNING_OBJECT (self, "Error during poll");
919                 return GST_FLOW_ERROR;
920         }
921 stopped:
922         {
923                 GST_WARNING_OBJECT (self, "Select stopped");
924                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
925                 return GST_FLOW_WRONG_STATE;
926         }
927 }
928
929 static gboolean
930 gst_dvbaudiosink_start (GstBaseSink * basesink)
931 {
932         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
933         gint control_sock[2];
934         self->fd = open("/dev/dvb/adapter0/audio0", O_RDWR);
935 //      self->fd = open("/dump.pes", O_RDWR|O_CREAT, 0555);
936
937         if (socketpair(PF_UNIX, SOCK_STREAM, 0, control_sock) < 0) {
938                 perror("socketpair");
939                 goto socket_pair;
940         }
941
942         READ_SOCKET (self) = control_sock[0];
943         WRITE_SOCKET (self) = control_sock[1];
944
945         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
946         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
947
948         if (self->fd)
949         {
950                 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY);
951                 ioctl(self->fd, AUDIO_PLAY);
952 //              ioctl(self->fd, AUDIO_SET_BYPASS_MODE, 0);
953         }
954         return TRUE;
955         /* ERRORS */
956 socket_pair:
957         {
958                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
959                                 GST_ERROR_SYSTEM);
960                 return FALSE;
961         }
962 }
963
964 static gboolean
965 gst_dvbaudiosink_stop (GstBaseSink * basesink)
966 {
967         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
968         if (self->fd >= 0)
969         {
970                 ioctl(self->fd, AUDIO_STOP);
971                 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX);
972
973                 int video_fd = open("/dev/dvb/adapter0/video0", O_RDWR);
974                 if ( video_fd > 0 )
975                 {
976                         ioctl(video_fd, VIDEO_SLOWMOTION, 0);
977                         ioctl(video_fd, VIDEO_FAST_FORWARD, 0);
978                         close (video_fd);
979                 }
980                 close(self->fd);
981         }
982
983         if (self->prev_data)
984                 gst_buffer_unref(self->prev_data);
985
986         return TRUE;
987 }
988
989 /* entry point to initialize the plug-in
990  * initialize the plug-in itself
991  * register the element factories and pad templates
992  * register the features
993  *
994  * exchange the string 'plugin' with your elemnt name
995  */
996 static gboolean
997 plugin_init (GstPlugin *plugin)
998 {
999         return gst_element_register (plugin, "dvbaudiosink",
1000                                                  GST_RANK_PRIMARY,
1001                                                  GST_TYPE_DVBAUDIOSINK);
1002 }
1003
1004 /* this is the structure that gstreamer looks for to register plugins
1005  *
1006  * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
1007  * description
1008  */
1009 GST_PLUGIN_DEFINE (
1010         GST_VERSION_MAJOR,
1011         GST_VERSION_MINOR,
1012         "dvb_audio_out",
1013         "DVB Audio Output",
1014         plugin_init,
1015         VERSION,
1016         "LGPL",
1017         "GStreamer",
1018         "http://gstreamer.net/"
1019 )