ease debugging overhead
[gst-plugin-dreamsource.git] / src / gstdreamaudiosource.c
1 /*
2  * GStreamer dreamaudiosource
3  * Copyright 2014-2015 Andreas Frisch <fraxinas@opendreambox.org>
4  *
5  * This program is licensed under the Creative Commons
6  * Attribution-NonCommercial-ShareAlike 3.0 Unported
7  * License. To view a copy of this license, visit
8  * http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
9  * Creative Commons,559 Nathan Abbott Way,Stanford,California 94305,USA.
10  *
11  * Alternatively, this program may be distributed and executed on
12  * hardware which is licensed by Dream Property GmbH.
13  *
14  * This program is NOT free software. It is open source, you are allowed
15  * to modify it (if you keep the license), but it may not be commercially
16  * distributed other than under the conditions noted above.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <gst/gst.h>
24 #include <sys/poll.h>
25 #include <sys/socket.h>
26 #include "gstdreamaudiosource.h"
27
28 #define CONTROL_STOP            'S'     /* stop the select call */
29 #define CONTROL_SOCKETS(src)   src->control_sock
30 #define WRITE_SOCKET(src)      src->control_sock[1]
31 #define READ_SOCKET(src)       src->control_sock[0]
32
33 #define SEND_COMMAND(src, command)          \
34 G_STMT_START {                              \
35   int G_GNUC_UNUSED _res; unsigned char c; c = command;   \
36   _res = write (WRITE_SOCKET(src), &c, 1);  \
37 } G_STMT_END
38
39 #define READ_COMMAND(src, command, res)        \
40 G_STMT_START {                                 \
41   res = read(READ_SOCKET(src), &command, 1);   \
42 } G_STMT_END
43
44
45 GST_DEBUG_CATEGORY_STATIC (dreamaudiosource_debug);
46 #define GST_CAT_DEFAULT dreamaudiosource_debug
47
48 enum
49 {
50         SIGNAL_GET_BASE_PTS,
51         LAST_SIGNAL
52 };
53 enum
54 {
55         ARG_0,
56         ARG_BITRATE,
57 };
58
59 static guint gst_dreamaudiosource_signals[LAST_SIGNAL] = { 0 };
60
61 #define DEFAULT_BITRATE 128
62
63 static GstStaticPadTemplate srctemplate =
64     GST_STATIC_PAD_TEMPLATE ("src",
65         GST_PAD_SRC,
66         GST_PAD_ALWAYS,
67         GST_STATIC_CAPS ("audio/mpeg, "
68         "mpegversion = 4,"
69         "stream-format = (string) adts")
70     );
71
72 #define gst_dreamaudiosource_parent_class parent_class
73 G_DEFINE_TYPE (GstDreamAudioSource, gst_dreamaudiosource, GST_TYPE_PUSH_SRC);
74
75 static GstCaps *gst_dreamaudiosource_getcaps (GstBaseSrc * psrc, GstCaps * filter);
76 static gboolean gst_dreamaudiosource_start (GstBaseSrc * bsrc);
77 static gboolean gst_dreamaudiosource_stop (GstBaseSrc * bsrc);
78 static gboolean gst_dreamaudiosource_unlock (GstBaseSrc * bsrc);
79 static void gst_dreamaudiosource_dispose (GObject * gobject);
80 static GstFlowReturn gst_dreamaudiosource_create (GstPushSrc * psrc, GstBuffer ** outbuf);
81
82 static void gst_dreamaudiosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
83 static void gst_dreamaudiosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
84
85 static GstStateChangeReturn gst_dreamaudiosource_change_state (GstElement * element, GstStateChange transition);
86 static gint64 gst_dreamaudiosource_get_base_pts (GstDreamAudioSource *self);
87
88 static void
89 gst_dreamaudiosource_class_init (GstDreamAudioSourceClass * klass)
90 {
91         GObjectClass *gobject_class;
92         GstElementClass *gstelement_class;
93         GstBaseSrcClass *gstbasesrc_class;
94         GstPushSrcClass *gstpush_src_class;
95
96         gobject_class = (GObjectClass *) klass;
97         gstelement_class = (GstElementClass *) klass;
98         gstbasesrc_class = (GstBaseSrcClass *) klass;
99         gstpush_src_class = (GstPushSrcClass *) klass;
100
101         gobject_class->set_property = gst_dreamaudiosource_set_property;
102         gobject_class->get_property = gst_dreamaudiosource_get_property;
103         gobject_class->dispose = gst_dreamaudiosource_dispose;
104
105         gst_element_class_add_pad_template (gstelement_class,
106                                             gst_static_pad_template_get (&srctemplate));
107
108         gst_element_class_set_static_metadata (gstelement_class,
109             "Dream Audio source", "Source/Audio",
110             "Provide an audio elementary stream from Dreambox encoder device",
111             "Andreas Frisch <fraxinas@opendreambox.org>");
112
113         gstelement_class->change_state = gst_dreamaudiosource_change_state;
114
115         gstbasesrc_class->get_caps = gst_dreamaudiosource_getcaps;
116         gstbasesrc_class->start = gst_dreamaudiosource_start;
117         gstbasesrc_class->stop = gst_dreamaudiosource_stop;
118         gstbasesrc_class->unlock = gst_dreamaudiosource_unlock;
119
120         gstpush_src_class->create = gst_dreamaudiosource_create;
121
122         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
123           g_param_spec_int ("bitrate", "Bitrate (kb/s)",
124             "Bitrate in kbit/sec", 16, 320, DEFAULT_BITRATE,
125             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
126
127         gst_dreamaudiosource_signals[SIGNAL_GET_BASE_PTS] =
128                 g_signal_new ("get-base-pts",
129                 G_TYPE_FROM_CLASS (klass),
130                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
131                 G_STRUCT_OFFSET (GstDreamAudioSourceClass, get_base_pts),
132                 NULL, NULL, gst_dreamsource_marshal_INT64__VOID, G_TYPE_INT64, 0);
133
134         klass->get_base_pts = gst_dreamaudiosource_get_base_pts;
135
136 }
137
138 static gint64
139 gst_dreamaudiosource_get_base_pts (GstDreamAudioSource *self)
140 {
141         GST_DEBUG_OBJECT (self, "gst_dreamaudiosource_get_base_pts %" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
142         return self->base_pts;
143 }
144
145 static void gst_dreamaudiosource_set_bitrate (GstDreamAudioSource * self, uint32_t bitrate)
146 {
147         if (!self->encoder || !self->encoder->fd)
148                 return;
149         uint32_t abr = bitrate*1000;
150         int ret = ioctl(self->encoder->fd, AENC_SET_BITRATE, &abr);
151         if (ret != 0)
152         {
153                 GST_WARNING_OBJECT (self, "can't set audio bitrate to %i bytes/s!", abr);
154                 return;
155         }
156         GST_INFO_OBJECT (self, "set audio bitrate to %i kBytes/s", bitrate);
157         self->audio_info.bitrate = abr;
158 }
159
160 gboolean
161 gst_dreamaudiosource_plugin_init (GstPlugin *plugin)
162 {
163         GST_DEBUG_CATEGORY_INIT (dreamaudiosource_debug, "dreamaudiosource", 0, "dreamaudiosource");
164         return gst_element_register (plugin, "dreamaudiosource", GST_RANK_PRIMARY, GST_TYPE_DREAMAUDIOSOURCE);
165 }
166
167 static void
168 gst_dreamaudiosource_init (GstDreamAudioSource * self)
169 {
170         self->encoder = NULL;
171         self->buffers_list = NULL;
172         self->descriptors_available = 0;
173
174         g_mutex_init (&self->mutex);
175         READ_SOCKET (self) = -1;
176         WRITE_SOCKET (self) = -1;
177
178         gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
179         gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
180
181         self->encoder = malloc(sizeof(EncoderInfo));
182
183         if(!self->encoder) {
184                 GST_ERROR_OBJECT(self,"out of space");
185                 return;
186         }
187
188         char fn_buf[32];
189         sprintf(fn_buf, "/dev/aenc%d", 0);
190         self->encoder->fd = open(fn_buf, O_RDWR | O_SYNC);
191         if(self->encoder->fd <= 0) {
192                 GST_ERROR_OBJECT(self,"cannot open device %s (%s)", fn_buf, strerror(errno));
193                 free(self->encoder);
194                 self->encoder = NULL;
195                 return;
196         }
197
198         int flags = fcntl(self->encoder->fd, F_GETFL, 0);
199         fcntl(self->encoder->fd, F_SETFL, flags | O_NONBLOCK);
200
201         self->encoder->buffer = malloc(ABUFSIZE);
202         if(!self->encoder->buffer) {
203                 GST_ERROR_OBJECT(self,"cannot alloc buffer");
204                 return;
205         }
206
207         self->encoder->cdb = (unsigned char *)mmap(0, AMMAPSIZE, PROT_READ, MAP_PRIVATE, self->encoder->fd, 0);
208         if(!self->encoder->cdb || self->encoder->cdb== MAP_FAILED) {
209                 GST_ERROR_OBJECT(self,"cannot mmap cdb: %s (%d)", strerror(errno));
210                 return;
211         }
212
213 #ifdef dump
214         self->dumpfd = open("/media/hdd/movie/dreamaudiosource.dump", O_WRONLY | O_CREAT | O_TRUNC);
215         GST_DEBUG_OBJECT (self, "dumpfd = %i (%s)", self->dumpfd, (self->dumpfd > 0) ? "OK" : strerror(errno));
216 #endif
217
218         gst_dreamaudiosource_set_bitrate(self, DEFAULT_BITRATE);
219 }
220
221 static void
222 gst_dreamaudiosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
223 {
224         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (object);
225
226         switch (prop_id) {
227                 case ARG_BITRATE:
228                         gst_dreamaudiosource_set_bitrate(self, g_value_get_int (value));
229                         break;
230                 default:
231                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232                         break;
233         }
234 }
235
236 static void
237 gst_dreamaudiosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
238 {
239         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (object);
240
241         switch (prop_id) {
242                 case ARG_BITRATE:
243                         g_value_set_int (value, self->audio_info.bitrate/1000);
244                         break;
245                 default:
246                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247                         break;
248         }
249 }
250
251 static GstCaps *
252 gst_dreamaudiosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
253 {
254         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
255         GstPadTemplate *pad_template;
256         GstCaps *caps;
257
258         pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS(self), "src");
259         g_return_val_if_fail (pad_template != NULL, NULL);
260
261         if (self->encoder == NULL) {
262                 GST_DEBUG_OBJECT (self, "encoder not opened -> use template caps");
263                 caps = gst_pad_template_get_caps (pad_template);
264         }
265         else
266         {
267                 caps = gst_caps_make_writable(gst_pad_template_get_caps (pad_template));
268         }
269
270         GST_DEBUG_OBJECT (self, "return caps %" GST_PTR_FORMAT, caps);
271         return caps;
272 }
273
274 static gboolean gst_dreamaudiosource_unlock (GstBaseSrc * bsrc)
275 {
276         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
277         GST_LOG_OBJECT (self, "stop creating buffers");
278         SEND_COMMAND (self, CONTROL_STOP);
279         return TRUE;
280 }
281
282 static void
283 gst_dreamaudiosource_free_buffer (struct _bufferdebug * bufferdebug)
284 {
285         GST_OBJECT_LOCK (bufferdebug->self);
286         GList *list = g_list_first (bufferdebug->self->buffers_list);
287         int count = 0;
288         while (list) {
289                 GST_TRACE_OBJECT (bufferdebug->self, "buffers_list[%i] = %" GST_PTR_FORMAT "", count, list->data);
290                 count++;
291                 list = g_list_next (list);
292         }
293         bufferdebug->self->buffers_list = g_list_remove(g_list_first (bufferdebug->self->buffers_list), bufferdebug->buffer);
294         GST_TRACE_OBJECT (bufferdebug->self, "removing %" GST_PTR_FORMAT " @ %" GST_TIME_FORMAT " from list -> new length=%i", bufferdebug->buffer, GST_TIME_ARGS (bufferdebug->buffer_pts), g_list_length(bufferdebug->self->buffers_list));
295         GST_OBJECT_UNLOCK (bufferdebug->self);
296 }
297
298 static GstFlowReturn
299 gst_dreamaudiosource_create (GstPushSrc * psrc, GstBuffer ** outbuf)
300 {
301         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (psrc);
302         EncoderInfo *enc = self->encoder;
303
304         static int dumpoffset;
305
306         GST_LOG_OBJECT (self, "new buffer requested");
307
308         if (!enc) {
309                 GST_WARNING_OBJECT (self, "encoder device not opened!");
310                 return GST_FLOW_ERROR;
311         }
312
313         while (1)
314         {
315                 *outbuf = NULL;
316
317                 if (self->descriptors_available == 0)
318                 {
319                         self->descriptors_count = 0;
320                         struct pollfd rfd[2];
321
322                         rfd[0].fd = enc->fd;
323                         rfd[0].events = POLLIN;
324                         rfd[1].fd = READ_SOCKET (self);
325                         rfd[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
326
327                         int ret = poll(rfd, 2, 200);
328
329                         if (G_UNLIKELY (ret == -1))
330                         {
331                                 GST_ERROR_OBJECT (self, "SELECT ERROR!");
332                                 return GST_FLOW_ERROR;
333                         }
334                         else if ( ret == 0 )
335                         {
336                                 GST_LOG_OBJECT (self, "SELECT TIMEOUT");
337                                 //!!! TODO generate dummy payload
338                                 *outbuf = gst_buffer_new();
339                         }
340                         else if ( G_UNLIKELY (rfd[1].revents) )
341                         {
342                                 char command;
343                                 READ_COMMAND (self, command, ret);
344                                 GST_LOG_OBJECT (self, "CONTROL_STOP!");
345                                 return GST_FLOW_FLUSHING;
346                         }
347                         else if ( G_LIKELY(rfd[0].revents & POLLIN) )
348                         {
349                                 int rlen = read(enc->fd, enc->buffer, ABUFSIZE);
350                                 if (rlen <= 0 || rlen % ABDSIZE ) {
351                                         if ( errno == 512 )
352                                                 return GST_FLOW_FLUSHING;
353                                         GST_WARNING_OBJECT (self, "read error %s (%i)", strerror(errno), errno);
354                                         return GST_FLOW_ERROR;
355                                 }
356                                 self->descriptors_available = rlen / ABDSIZE;
357                                 GST_LOG_OBJECT (self, "encoder buffer was empty, %d descriptors available", self->descriptors_available);
358                         }
359                 }
360
361                 while (self->descriptors_count < self->descriptors_available) {
362                         off_t offset = self->descriptors_count * ABDSIZE;
363                         AudioBufferDescriptor *desc = (AudioBufferDescriptor*)(&enc->buffer[offset]);
364
365                         uint32_t f = desc->stCommon.uiFlags;
366
367                         GST_LOG_OBJECT (self, "descriptors_count=%d, descriptors_available=%u\tuiOffset=%u, uiLength=%"G_GSIZE_FORMAT"", self->descriptors_count, self->descriptors_available, desc->stCommon.uiOffset, desc->stCommon.uiLength);
368
369                         if (f & CDB_FLAG_METADATA) {
370                                 GST_LOG_OBJECT (self, "CDB_FLAG_METADATA... skip outdated packet");
371                                 self->descriptors_count = self->descriptors_available;
372                                 continue;
373                         }
374
375                         struct _bufferdebug * bdg = NULL;
376                         GDestroyNotify buffer_free_func = NULL;
377                         if ( gst_debug_category_get_threshold (dreamaudiosource_debug) >= GST_LEVEL_TRACE)
378                         {
379                                 bdg = malloc(sizeof(struct _bufferdebug));
380                                 buffer_free_func = (GDestroyNotify) gst_dreamaudiosource_free_buffer;
381                         }
382
383                         *outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, enc->cdb, AMMAPSIZE, desc->stCommon.uiOffset, desc->stCommon.uiLength, bdg, buffer_free_func);
384
385                         if (bdg)
386                         {
387                                 bdg->self = self;
388                                 bdg->buffer = *outbuf;
389                                 self->buffers_list = g_list_append(self->buffers_list, *outbuf);
390                         }
391
392                         if (f & CDB_FLAG_PTS_VALID)
393                         {
394                                 if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
395                                 {
396                                         if (self->dreamvideosrc)
397                                         {
398                                                 g_mutex_lock (&self->mutex);
399                                                 guint64 videosource_base_pts;
400                                                 g_signal_emit_by_name(self->dreamvideosrc, "get-base-pts", &videosource_base_pts);
401                                                 if (videosource_base_pts != GST_CLOCK_TIME_NONE)
402                                                 {
403                                                         GST_DEBUG_OBJECT (self, "use DREAMVIDEOSOURCE's base_pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (videosource_base_pts) );
404                                                         self->base_pts = videosource_base_pts;
405                                                 }
406                                                 g_mutex_unlock (&self->mutex);
407                                         }
408                                         else
409                                         {
410                                                 self->base_pts = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
411                                                 GST_DEBUG_OBJECT (self, "use mpeg stream pts as base_pts=%" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
412                                         }
413                                 }
414                                 GstClockTime buffer_time = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
415                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_time > self->base_pts )
416                                 {
417                                         buffer_time -= self->base_pts;
418                                         GST_BUFFER_PTS(*outbuf) = buffer_time;
419                                         GST_BUFFER_DTS(*outbuf) = buffer_time;
420                                 }
421                                 if (bdg)
422                                         bdg->buffer_pts = buffer_time;
423                         }
424
425 #ifdef dump
426                         int wret = write(self->dumpfd, (unsigned char*)(enc->cdb + desc->stCommon.uiOffset), desc->stCommon.uiLength);
427                         dumpoffset += wret;
428                         GST_LOG_OBJECT (self, "read %"G_GSIZE_FORMAT" dumped %i total 0x%08X", desc->stCommon.uiLength, wret, dumpoffset );
429 #endif
430                         self->descriptors_count++;
431
432                         break;
433                 }
434
435                 if (self->descriptors_count == self->descriptors_available) {
436                         GST_LOG_OBJECT (self, "self->descriptors_count == self->descriptors_available -> release %i consumed descriptors", self->descriptors_count);
437                         /* release consumed descs */
438                         if (write(enc->fd, &self->descriptors_count, 4) != 4) {
439                                 GST_WARNING_OBJECT (self, "release consumed descs write error!");
440                                 return GST_FLOW_ERROR;
441                         }
442                         self->descriptors_available = 0;
443                 }
444
445                 if (*outbuf)
446                 {
447                         GST_DEBUG_OBJECT (self, "pushing %" GST_PTR_FORMAT "", *outbuf );
448                         return GST_FLOW_OK;
449                 }
450         }
451
452         return GST_FLOW_ERROR;
453 }
454
455 static GstStateChangeReturn gst_dreamaudiosource_change_state (GstElement * element, GstStateChange transition)
456 {
457         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (element);
458         int ret;
459         switch (transition) {
460                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
461                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
462                         self->base_pts = GST_CLOCK_TIME_NONE;
463                         ret = ioctl(self->encoder->fd, AENC_START);
464                         if ( ret != 0 )
465                         {
466                                 GST_ERROR_OBJECT(self,"can't start encoder ioctl!");
467                                 return GST_STATE_CHANGE_FAILURE;
468                         }
469                         self->descriptors_available = 0;
470                         GST_INFO_OBJECT (self, "started encoder!");
471                         break;
472                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
473                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED self->descriptors_count=%i self->descriptors_available=%i", self->descriptors_count, self->descriptors_available);
474                         GST_OBJECT_LOCK (self);
475                         while (self->descriptors_count < self->descriptors_available)
476                                 GST_LOG_OBJECT (self, "flushing self->descriptors_count=%i", self->descriptors_count++);
477                         if (self->descriptors_count)
478                                 write(self->encoder->fd, &self->descriptors_count, 4);
479                         ret = ioctl(self->encoder->fd, AENC_STOP);
480                         GST_OBJECT_UNLOCK (self);
481                         if ( ret != 0 )
482                         {
483                                 GST_ERROR_OBJECT(self,"can't stop encoder ioctl!");
484                                 return GST_STATE_CHANGE_FAILURE;
485                         }
486                         GST_INFO_OBJECT (self, "stopped encoder!");
487                         break;
488                 default:
489                         break;
490         }
491         if (GST_ELEMENT_CLASS (parent_class)->change_state)
492                 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
493         return GST_STATE_CHANGE_SUCCESS;
494 }
495
496 static gboolean
497 gst_dreamaudiosource_start (GstBaseSrc * bsrc)
498 {
499         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
500         self->dreamvideosrc = gst_bin_get_by_name_recurse_up(GST_BIN(GST_ELEMENT_PARENT(self)), "dreamvideosource0");
501
502         int control_sock[2];
503         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
504         {
505                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM);
506                 return FALSE;
507         }
508         READ_SOCKET (self) = control_sock[0];
509         WRITE_SOCKET (self) = control_sock[1];
510         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
511         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
512
513         GST_DEBUG_OBJECT (self, "started. reference to dreamvideosource=%" GST_PTR_FORMAT"", self->dreamvideosrc);
514         return TRUE;
515 }
516
517 static gboolean
518 gst_dreamaudiosource_stop (GstBaseSrc * bsrc)
519 {
520         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
521         if (self->dreamvideosrc)
522                 gst_object_unref(self->dreamvideosrc);
523         GST_DEBUG_OBJECT (self, "stop");
524         return TRUE;
525 }
526
527 static void
528 gst_dreamaudiosource_dispose (GObject * gobject)
529 {
530         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (gobject);
531         if (self->encoder) {
532                 if (self->encoder->buffer)
533                         free(self->encoder->buffer);
534                 if (self->encoder->cdb)
535                         munmap(self->encoder->cdb, AMMAPSIZE);
536                 if (self->encoder->fd)
537                         close(self->encoder->fd);
538                 free(self->encoder);
539         }
540 #ifdef dump
541         close(self->dumpfd);
542 #endif
543         g_list_free(self->buffers_list);
544         g_mutex_clear (&self->mutex);
545         GST_DEBUG_OBJECT (self, "disposed");
546         G_OBJECT_CLASS (parent_class)->dispose (gobject);
547 }