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