use correct streamtype for mpeg4 aac
[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 <fcntl.h>
69 #include <poll.h>
70
71 #include <gst/gst.h>
72
73 /* We add a control socket as in fdsrc to make it shutdown quickly when it's blocking on the fd.
74  * Poll is used to determine when the fd is ready for use. When the element state is changed,
75  * it happens from another thread while fdsink is select'ing on the fd. The state-change thread 
76  * sends a control message, so fdsink wakes up and changes state immediately otherwise
77  * it would stay blocked until it receives some data. */
78
79 /* the poll call is also performed on the control sockets, that way
80  * we can send special commands to unblock the select call */
81 #define CONTROL_STOP                                            'S'              /* stop the select call */
82 #define CONTROL_SOCKETS(sink)    sink->control_sock
83 #define WRITE_SOCKET(sink)                      sink->control_sock[1]
84 #define READ_SOCKET(sink)                        sink->control_sock[0]
85
86 #define SEND_COMMAND(sink, command)                                     \
87 G_STMT_START {                                                                                                                  \
88         unsigned char c; c = command;                                            \
89         write (WRITE_SOCKET(sink), &c, 1);                               \
90 } G_STMT_END
91
92 #define READ_COMMAND(sink, command, res)                                \
93 G_STMT_START {                                                                                                                           \
94         res = read(READ_SOCKET(sink), &command, 1);      \
95 } G_STMT_END
96
97 #include "gstdvbaudiosink.h"
98
99 #ifndef AUDIO_GET_PTS
100 #define AUDIO_GET_PTS              _IOR('o', 19, gint64)
101 #endif
102
103 GST_DEBUG_CATEGORY_STATIC (dvbaudiosink_debug);
104 #define GST_CAT_DEFAULT dvbaudiosink_debug
105
106 /* Filter signals and args */
107 enum {
108         /* FILL ME */
109         LAST_SIGNAL
110 };
111
112 enum {
113         ARG_0,
114         ARG_SILENT
115 };
116
117 static GstStaticPadTemplate sink_factory =
118 GST_STATIC_PAD_TEMPLATE (
119         "sink",
120         GST_PAD_SINK,
121         GST_PAD_ALWAYS,
122         GST_STATIC_CAPS ("audio/mpeg, "
123                 "mpegversion = (int) { 1, 2, 4 }; "
124                 "audio/x-private1-ac3; "
125                 "audio/x-ac3; "
126                 "audio/x-dts")
127 );
128
129 #define DEBUG_INIT(bla) \
130         GST_DEBUG_CATEGORY_INIT (dvbaudiosink_debug, "dvbaudiosink", 0, "dvbaudiosink element");
131
132 GST_BOILERPLATE_FULL (GstDVBAudioSink, gst_dvbaudiosink, GstBaseSink,
133         GST_TYPE_BASE_SINK, DEBUG_INIT);
134
135 static void     gst_dvbaudiosink_set_property (GObject *object, guint prop_id,
136                                                                                                                                                                                                         const GValue *value,
137                                                                                                                                                                                                         GParamSpec *pspec);
138 static void     gst_dvbaudiosink_get_property (GObject *object, guint prop_id,
139                                                                                                                                                                                                         GValue *value,
140                                                                                                                                                                                                         GParamSpec *pspec);
141
142 static gboolean gst_dvbaudiosink_start (GstBaseSink * sink);
143 static gboolean gst_dvbaudiosink_stop (GstBaseSink * sink);
144 static gboolean gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event);
145 static GstFlowReturn gst_dvbaudiosink_render (GstBaseSink * sink,
146         GstBuffer * buffer);
147 static gboolean gst_dvbaudiosink_query (GstElement * element, GstQuery * query);
148 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink);
149 static gboolean gst_dvbaudiosink_set_caps (GstBaseSink * sink, GstCaps * caps);
150
151 gboolean bypass_set = FALSE;
152
153 static void
154 gst_dvbaudiosink_base_init (gpointer klass)
155 {
156         static GstElementDetails element_details = {
157                 "A DVB audio sink",
158                 "Generic/DVBAudioSink",
159                 "Outputs a MPEG2 PES / ES into a DVB audio device for hardware playback",
160                 "Felix Domke <tmbinc@elitedvb.net>"
161         };
162         GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
163
164         gst_element_class_add_pad_template (element_class,
165                 gst_static_pad_template_get (&sink_factory));
166         gst_element_class_set_details (element_class, &element_details);
167 }
168
169 /* initialize the plugin's class */
170 static void
171 gst_dvbaudiosink_class_init (GstDVBAudioSinkClass *klass)
172 {
173         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
174         GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
175         
176         gobject_class->set_property = gst_dvbaudiosink_set_property;
177         gobject_class->get_property = gst_dvbaudiosink_get_property;
178         
179         gobject_class = G_OBJECT_CLASS (klass);
180         g_object_class_install_property (gobject_class, ARG_SILENT,
181                 g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
182                                                                                                         FALSE, G_PARAM_READWRITE));
183
184         gstbasesink_class->get_times = NULL;
185         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_start);
186         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_stop);
187         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_render);
188         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_event);
189         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_unlock);
190         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_set_caps);
191         GST_ELEMENT_CLASS (klass)->query = GST_DEBUG_FUNCPTR(gst_dvbaudiosink_query);
192 }
193
194 /* initialize the new element
195  * instantiate pads and add them to element
196  * set functions
197  * initialize structure
198  */
199 static void
200 gst_dvbaudiosink_init (GstDVBAudioSink *klass,
201                 GstDVBAudioSinkClass * gclass)
202 {
203         klass->silent = FALSE;
204         klass->aac_adts_header_valid = FALSE;
205
206         GST_BASE_SINK (klass)->sync = FALSE;
207 }
208
209 static void
210 gst_dvbaudiosink_set_property (GObject *object, guint prop_id,
211                                                                                                                                         const GValue *value, GParamSpec *pspec)
212 {
213         GstDVBAudioSink *filter;
214
215         g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
216         filter = GST_DVBAUDIOSINK (object);
217
218         switch (prop_id)
219         {
220         case ARG_SILENT:
221                 filter->silent = g_value_get_boolean (value);
222                 break;
223         default:
224                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225                 break;
226         }
227 }
228
229 static void
230 gst_dvbaudiosink_get_property (GObject *object, guint prop_id,
231                                                                                                                                         GValue *value, GParamSpec *pspec)
232 {
233         GstDVBAudioSink *filter;
234
235         g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
236         filter = GST_DVBAUDIOSINK (object);
237
238         switch (prop_id) {
239         case ARG_SILENT:
240                 g_value_set_boolean (value, filter->silent);
241                 break;
242         default:
243                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
244                 break;
245         }
246 }
247
248 static gboolean
249 gst_dvbaudiosink_query (GstElement * element, GstQuery * query)
250 {
251         GstDVBAudioSink *self = GST_DVBAUDIOSINK (element);
252
253 //      printf("query %d %d\n", GST_QUERY_TYPE(query), GST_QUERY_POSITION);
254
255         switch (GST_QUERY_TYPE (query)) {
256         case GST_QUERY_POSITION:
257         {
258                 gint64 cur = 0;
259                 GstFormat format;
260
261                 gst_query_parse_position (query, &format, NULL);
262
263                 if (format != GST_FORMAT_TIME)
264                         goto query_default;
265
266                 ioctl(self->fd, AUDIO_GET_PTS, &cur);
267 //              printf("PTS: %08llx", cur);
268
269                 cur *= 11111;
270
271                 gst_query_set_position (query, format, cur);
272
273                 GST_DEBUG_OBJECT (self, "position format %d", format);
274                 return TRUE;
275         }
276         default:
277 query_default:
278                 return GST_ELEMENT_CLASS (parent_class)->query (element, query);
279         }
280 }
281
282 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink)
283 {
284         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
285
286         SEND_COMMAND (self, CONTROL_STOP);
287
288         return TRUE;
289 }
290
291 static gboolean 
292 gst_dvbaudiosink_set_caps (GstBaseSink * basesink, GstCaps * caps)
293 {
294         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
295         GstStructure *structure = gst_caps_get_structure (caps, 0);
296         const char *type = gst_structure_get_name (structure);
297         int bypass = -1;
298
299         self->skip = 0;
300         if (!strcmp(type, "audio/mpeg")) {
301                 gint mpegversion;
302                 gst_structure_get_int (structure, "mpegversion", &mpegversion);
303                 switch (mpegversion) {
304                         case 1:
305                         {
306                                 gint layer;
307                                 gst_structure_get_int (structure, "layer", &layer);
308                                 if ( layer == 3 )
309                                         bypass = 0xA;
310                                 else
311                                         bypass = 1;
312                                 printf("MIMETYPE %s version %d layer %d\n",type,mpegversion,layer);
313                                 break;
314                         }
315                         case 2:
316                                 bypass = 8;
317                         case 4:
318                         {
319                                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
320                                 printf("MIMETYPE %s version %d (AAC)\n", type, mpegversion);
321                                 if (codec_data) {
322                                         guint8 *h = GST_BUFFER_DATA(gst_value_get_buffer (codec_data));
323                                         guint8 obj_type = ((h[0] & 0xC) >> 2) + 1;
324                                         guint8 rate_idx = ((h[0] & 0x3) << 1) | ((h[1] & 0x80) >> 7);
325                                         guint8 channels = (h[1] & 0x78) >> 3;
326 //                                      printf("have codec data -> obj_type = %d, rate_idx = %d, channels = %d\n",
327 //                                              obj_type, rate_idx, channels);
328                                         /* Sync point over a full byte */
329                                         self->aac_adts_header[0] = 0xFF;
330                                         /* Sync point continued over first 4 bits + static 4 bits
331                                          * (ID, layer, protection)*/
332                                         self->aac_adts_header[1] = 0xF1;
333                                         /* Object type over first 2 bits */
334                                         self->aac_adts_header[2] = obj_type << 6;
335                                         /* rate index over next 4 bits */
336                                         self->aac_adts_header[2] |= rate_idx << 2;
337                                         /* channels over last 2 bits */
338                                         self->aac_adts_header[2] |= (channels & 0x4) >> 2;
339                                         /* channels continued over next 2 bits + 4 bits at zero */
340                                         self->aac_adts_header[3] = (channels & 0x3) << 6;
341                                         self->aac_adts_header_valid = TRUE;
342                                 }
343                                 else
344                                         printf("no codec data!!!\n");
345                                 if (bypass == -1)
346                                         bypass = 0x0b;
347                                 break;
348                         }
349                         default:
350                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
351                                 break;
352                 }
353         }
354         else if (!strcmp(type, "audio/x-ac3") || !strcmp(type, "audio/ac3"))
355         {
356                 printf("MIMETYPE %s\n",type);
357                 bypass = 0;
358         }
359         else if (!strcmp(type, "audio/x-private1-dts"))
360         {
361                 printf("MIMETYPE %s (DVD Audio - 2 byte skipping)\n",type);
362                 bypass = 2;
363                 self->skip = 2;
364         }
365         else if (!strcmp(type, "audio/x-private1-ac3"))
366         {
367                 printf("MIMETYPE %s (DVD Audio - 2 byte skipping)\n",type);
368                 bypass = 0;
369                 self->skip = 2;
370         } 
371         else if (!strcmp(type, "audio/x-dts") || !strcmp(type, "audio/dts"))
372         {
373                 printf("MIMETYPE %s\n",type);
374                 bypass = 2;
375                 GST_ELEMENT_ERROR (self, STREAM, CODEC_NOT_FOUND, (NULL), ("DTS not yet handled by driver"));
376                 return FALSE;
377         } else
378         {
379                 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", type));
380                 return FALSE;
381         }
382
383         GST_DEBUG_OBJECT(self, "setting dvb mode 0x%02x\n", bypass);
384
385         if (ioctl(self->fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
386         {
387                 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL), ("hardware decoder can't be set to bypass mode %i", bypass));
388                 return FALSE;
389         }
390         bypass_set = TRUE;
391         return TRUE;
392 }
393
394 static gboolean
395 gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event)
396 {
397         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
398         GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
399
400         switch (GST_EVENT_TYPE (event)) {
401         case GST_EVENT_FLUSH_START:
402                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
403                 break;
404         case GST_EVENT_FLUSH_STOP:
405                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
406                 while (1)
407                 {
408                         gchar command;
409                         int res;
410
411                         READ_COMMAND (self, command, res);
412                         if (res < 0)
413                                 break;
414                 }
415                 break;
416         case GST_EVENT_EOS:
417         {
418                 struct pollfd pfd[2];
419                 int retval;
420                 pfd[0].fd = READ_SOCKET(self);
421                 pfd[0].events = POLLIN;
422                 
423 #if 0
424                         /* needs driver support */
425                 pfd[1].fd = self->fd;
426                 pfd[1].events = POLLHUP;
427
428                 do {
429                         GST_DEBUG_OBJECT (self, "going into poll to wait for EOS");
430                         retval = poll(pfd, 2, -1);
431                 } while ((retval == -1 && errno == EINTR));
432                 
433                 if (pfd[0].revents & POLLIN) /* flush */
434                         break;
435                 GST_DEBUG_OBJECT (self, "EOS wait ended because of buffer empty. now waiting for PTS %llx", self->pts_eos);
436 #endif
437
438                 do {
439                         unsigned long long cur;
440                         ioctl(self->fd, AUDIO_GET_PTS, &cur);
441                         
442                         long long diff = self->last_pts_eos - cur;
443                         
444                         GST_DEBUG_OBJECT (self, "at %llx (diff %llx)", cur, diff);
445                         
446                         if (diff <= 0x1000)
447                                 break;
448
449                         retval = poll(pfd, 1, 1000);
450                                 /* check for flush */
451                         if (pfd[0].revents & POLLIN)
452                                 break;
453                 } while (1);
454
455                 break;
456         }
457         default:
458                 break;
459         }
460         return TRUE;
461 }
462
463 static GstFlowReturn
464 gst_dvbaudiosink_render (GstBaseSink * sink, GstBuffer * buffer)
465 {
466         GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
467         unsigned char pes_header[64];
468         int skip = self->skip;
469         unsigned int size = GST_BUFFER_SIZE (buffer) - skip;
470         unsigned char *data = GST_BUFFER_DATA (buffer) + skip;
471         gint retval;
472         size_t pes_header_size;
473         struct pollfd pfd[2];
474
475 //      int i=0;
476 //      for (;i < (size > 0x1F ? 0x1F : size); ++i)
477 //              printf("%02x ", data[i]);
478 //      printf("%d bytes\n", size);
479 //      printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
480
481         if ( !bypass_set )
482         {
483                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("hardware decoder not setup (no caps in pipeline?)"));
484                 return GST_FLOW_ERROR;
485         }
486
487         pfd[0].fd = READ_SOCKET(self);
488         pfd[0].events = POLLIN;
489         pfd[1].fd = self->fd;
490         pfd[1].events = POLLOUT;
491
492         do {
493                 GST_DEBUG_OBJECT (self, "going into poll, have %d bytes to write",
494                                 size);
495                 retval = poll(pfd, 2, -1);
496         } while ((retval == -1 && errno == EINTR));
497
498         if (retval == -1)
499                 goto poll_error;
500
501         if (pfd[0].revents & POLLIN) {
502                 /* read all stop commands */
503                 while (TRUE) {
504                         gchar command;
505                         int res;
506
507                         READ_COMMAND (self, command, res);
508                         if (res < 0) {
509                                 GST_LOG_OBJECT (self, "no more commands");
510                                 /* no more commands */
511                                 break;
512                         }
513                 }
514                 goto stopped;
515         }
516         
517         if (self->fd < 0)
518                 return GST_FLOW_OK;
519
520         pes_header[0] = 0;
521         pes_header[1] = 0;
522         pes_header[2] = 1;
523         pes_header[3] = 0xC0;
524
525         if (self->aac_adts_header_valid)
526                 size += 7;
527
528                 /* do we have a timestamp? */
529         if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE)
530         {
531                 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
532
533                 self->last_pts_eos = self->pts_eos;
534                 self->pts_eos = pts;
535
536                 pes_header[4] = (size + 8) >> 8;
537                 pes_header[5] = (size + 8) & 0xFF;
538                 
539                 pes_header[6] = 0x80;
540                 pes_header[7] = 0x80;
541                 
542                 pes_header[8] = 5;
543                 
544                 pes_header[9]  = 0x21 | ((pts >> 29) & 0xE);
545                 pes_header[10] = pts >> 22;
546                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
547                 pes_header[12] = pts >> 7;
548                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
549                 pes_header_size = 14;
550         } else
551         {
552                 pes_header[4] = (size + 3) >> 8;
553                 pes_header[5] = (size + 3) & 0xFF;
554                 pes_header[6] = 0x80;
555                 pes_header[7] = 0x00;
556                 pes_header[8] = 0;
557                 pes_header_size = 9;
558         }
559
560         if (self->aac_adts_header_valid) {
561                 self->aac_adts_header[3] &= 0xC0;
562                 /* frame size over last 2 bits */
563                 self->aac_adts_header[3] |= (size & 0x1800) >> 11;
564                 /* frame size continued over full byte */
565                 self->aac_adts_header[4] = (size & 0x1FF8) >> 3;
566                 /* frame size continued first 3 bits */
567                 self->aac_adts_header[5] = (size & 7) << 5;
568                 /* buffer fullness (0x7FF for VBR) over 5 last bits */
569                 self->aac_adts_header[5] |= 0x1F;
570                 /* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for
571                  * number of raw data blocks */
572                 self->aac_adts_header[6] = 0xFC;
573                 memcpy(pes_header + pes_header_size, self->aac_adts_header, 7);
574                 pes_header_size += 7;
575         }
576
577         write(self->fd, pes_header, pes_header_size);
578         write(self->fd, data, GST_BUFFER_SIZE (buffer) - skip);
579
580         return GST_FLOW_OK;
581 poll_error:
582         {
583                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
584                                 ("poll on file descriptor: %s.", g_strerror (errno)));
585                 GST_DEBUG_OBJECT (self, "Error during poll");
586                 return GST_FLOW_ERROR;
587         }
588 stopped:
589         {
590                 GST_DEBUG_OBJECT (self, "Select stopped");
591                 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
592                 return GST_FLOW_WRONG_STATE;
593         }
594 }
595
596 static gboolean
597 gst_dvbaudiosink_start (GstBaseSink * basesink)
598 {
599         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
600         self->fd = open("/dev/dvb/adapter0/audio0", O_RDWR);
601 //      self->fd = open("/dump.pes", O_RDWR|O_CREAT, 0555);
602         
603         gint control_sock[2];
604
605         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
606                 goto socket_pair;
607
608         READ_SOCKET (self) = control_sock[0];
609         WRITE_SOCKET (self) = control_sock[1];
610
611         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
612         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
613
614         if (self->fd)
615         {
616                 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY);
617                 ioctl(self->fd, AUDIO_PLAY);
618 //              ioctl(self->fd, AUDIO_SET_BYPASS_MODE, 0);
619         }
620         return TRUE;
621         /* ERRORS */
622 socket_pair:
623         {
624                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
625                                 GST_ERROR_SYSTEM);
626                 return FALSE;
627         }
628 }
629
630 static gboolean
631 gst_dvbaudiosink_stop (GstBaseSink * basesink)
632 {
633         GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
634         if (self->fd >= 0)
635         {
636                 ioctl(self->fd, AUDIO_STOP);
637                 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX);
638                 close(self->fd);
639         }
640
641         return TRUE;
642 }
643
644 /* entry point to initialize the plug-in
645  * initialize the plug-in itself
646  * register the element factories and pad templates
647  * register the features
648  *
649  * exchange the string 'plugin' with your elemnt name
650  */
651 static gboolean
652 plugin_init (GstPlugin *plugin)
653 {
654         return gst_element_register (plugin, "dvbaudiosink",
655                                                  GST_RANK_PRIMARY,
656                                                  GST_TYPE_DVBAUDIOSINK);
657 }
658
659 /* this is the structure that gstreamer looks for to register plugins
660  *
661  * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
662  * description
663  */
664 GST_PLUGIN_DEFINE (
665         GST_VERSION_MAJOR,
666         GST_VERSION_MINOR,
667         "dvb_audio_out",
668         "DVB Audio Output",
669         plugin_init,
670         VERSION,
671         "LGPL",
672         "GStreamer",
673         "http://gstreamer.net/"
674 )