error out on state change to ready if encoder device is unavailable
[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 "gstdreamaudiosource.h"
25
26 GST_DEBUG_CATEGORY_STATIC (dreamaudiosource_debug);
27 #define GST_CAT_DEFAULT dreamaudiosource_debug
28
29 GType gst_dreamaudiosource_input_mode_get_type (void)
30 {
31         static volatile gsize input_mode_type = 0;
32         static const GEnumValue input_mode[] = {
33                 {GST_DREAMAUDIOSOURCE_INPUT_MODE_LIVE, "GST_DREAMAUDIOSOURCE_INPUT_MODE_LIVE", "live"},
34                 {GST_DREAMAUDIOSOURCE_INPUT_MODE_HDMI_IN, "GST_DREAMAUDIOSOURCE_INPUT_MODE_HDMI_IN", "hdmi_in"},
35                 {GST_DREAMAUDIOSOURCE_INPUT_MODE_BACKGROUND, "GST_DREAMAUDIOSOURCE_INPUT_MODE_BACKGROUND", "background"},
36                 {0, NULL, NULL},
37         };
38
39         if (g_once_init_enter (&input_mode_type)) {
40                 GType tmp = g_enum_register_static ("GstDreamAudioSourceInputMode", input_mode);
41                 g_once_init_leave (&input_mode_type, tmp);
42         }
43         return (GType) input_mode_type;
44 }
45
46 enum
47 {
48         SIGNAL_GET_BASE_PTS,
49         LAST_SIGNAL
50 };
51 enum
52 {
53         ARG_0,
54         ARG_BITRATE,
55         ARG_INPUT_MODE
56 };
57
58 static guint gst_dreamaudiosource_signals[LAST_SIGNAL] = { 0 };
59
60 #define DEFAULT_BITRATE    128
61 #define DEFAULT_INPUT_MODE GST_DREAMAUDIOSOURCE_INPUT_MODE_LIVE
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 * bsrc, 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 #ifdef PROVIDE_CLOCK
89 static GstClock *gst_dreamaudiosource_provide_clock (GstElement * elem);
90 // static GstClockTime gst_dreamaudiosource_get_encoder_time_ (GstClock * clock, GstBaseSrc * bsrc);
91 #endif
92
93 static void
94 gst_dreamaudiosource_class_init (GstDreamAudioSourceClass * klass)
95 {
96         GObjectClass *gobject_class;
97         GstElementClass *gstelement_class;
98         GstBaseSrcClass *gstbasesrc_class;
99         GstPushSrcClass *gstpush_src_class;
100
101         gobject_class = (GObjectClass *) klass;
102         gstelement_class = (GstElementClass *) klass;
103         gstbasesrc_class = (GstBaseSrcClass *) klass;
104         gstpush_src_class = (GstPushSrcClass *) klass;
105
106         gobject_class->set_property = gst_dreamaudiosource_set_property;
107         gobject_class->get_property = gst_dreamaudiosource_get_property;
108         gobject_class->dispose = gst_dreamaudiosource_dispose;
109
110         gst_element_class_add_pad_template (gstelement_class,
111                                             gst_static_pad_template_get (&srctemplate));
112
113         gst_element_class_set_static_metadata (gstelement_class,
114             "Dream Audio source", "Source/Audio",
115             "Provide an audio elementary stream from Dreambox encoder device",
116             "Andreas Frisch <fraxinas@opendreambox.org>");
117
118         gstelement_class->change_state = gst_dreamaudiosource_change_state;
119
120         gstbasesrc_class->get_caps = gst_dreamaudiosource_getcaps;
121         gstbasesrc_class->start = gst_dreamaudiosource_start;
122         gstbasesrc_class->stop = gst_dreamaudiosource_stop;
123         gstbasesrc_class->unlock = gst_dreamaudiosource_unlock;
124
125         gstpush_src_class->create = gst_dreamaudiosource_create;
126
127 #ifdef PROVIDE_CLOCK
128         gstelement_class->provide_clock = GST_DEBUG_FUNCPTR (gst_dreamaudiosource_provide_clock);
129 //      g_type_class_ref (GST_TYPE_SYSTEM_CLOCK);
130 #endif
131
132         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
133           g_param_spec_int ("bitrate", "Bitrate (kb/s)",
134             "Bitrate in kbit/sec", 16, 320, DEFAULT_BITRATE,
135             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
136
137         g_object_class_install_property (gobject_class, ARG_INPUT_MODE,
138           g_param_spec_enum ("input-mode", "Input Mode",
139             "Select the input source of the audio stream",
140             GST_TYPE_DREAMAUDIOSOURCE_INPUT_MODE, DEFAULT_INPUT_MODE,
141             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
142
143         gst_dreamaudiosource_signals[SIGNAL_GET_BASE_PTS] =
144                 g_signal_new ("get-base-pts",
145                 G_TYPE_FROM_CLASS (klass),
146                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
147                 G_STRUCT_OFFSET (GstDreamAudioSourceClass, get_base_pts),
148                 NULL, NULL, gst_dreamsource_marshal_INT64__VOID, G_TYPE_INT64, 0);
149
150         klass->get_base_pts = gst_dreamaudiosource_get_base_pts;
151
152 }
153
154 static gint64
155 gst_dreamaudiosource_get_base_pts (GstDreamAudioSource *self)
156 {
157         GST_DEBUG_OBJECT (self, "gst_dreamaudiosource_get_base_pts %" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
158         return self->base_pts;
159 }
160
161 static void gst_dreamaudiosource_set_bitrate (GstDreamAudioSource * self, uint32_t bitrate)
162 {
163         if (!self->encoder || !self->encoder->fd)
164                 return;
165         uint32_t abr = bitrate*1000;
166         int ret = ioctl(self->encoder->fd, AENC_SET_BITRATE, &abr);
167         if (ret != 0)
168         {
169                 GST_WARNING_OBJECT (self, "can't set audio bitrate to %i bytes/s!", abr);
170                 return;
171         }
172         GST_INFO_OBJECT (self, "set audio bitrate to %i kBytes/s", bitrate);
173         self->audio_info.bitrate = abr;
174 }
175
176 void gst_dreamaudiosource_set_input_mode (GstDreamAudioSource *self, GstDreamAudioSourceInputMode mode)
177 {
178         g_return_if_fail (GST_IS_DREAMAUDIOSOURCE (self));
179         GEnumValue *val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (GST_TYPE_DREAMAUDIOSOURCE_INPUT_MODE)), mode);
180         if (!val)
181         {
182                 GST_ERROR_OBJECT (self, "no such input_mode %i!", mode);
183                 goto out;
184         }
185         const gchar *value_nick = val->value_nick;
186         GST_DEBUG_OBJECT (self, "setting input_mode to %s (%i)...", value_nick, mode);
187         g_mutex_lock (&self->mutex);
188         if (!self->encoder || !self->encoder->fd)
189         {
190                 GST_ERROR_OBJECT (self, "can't set input mode because encoder device not opened!");
191                 goto out;
192         }
193         int int_mode = mode;
194         int ret = ioctl(self->encoder->fd, AENC_SET_SOURCE, &int_mode);
195         if (ret != 0)
196         {
197                 GST_WARNING_OBJECT (self, "can't set input mode to %s (%i) error: %s", value_nick, mode, strerror(errno));
198                 goto out;
199         }
200         GST_INFO_OBJECT (self, "successfully set input mode to %s (%i)", value_nick, mode);
201         self->input_mode = mode;
202 out:
203         g_mutex_unlock (&self->mutex);
204         return;
205 }
206
207 GstDreamAudioSourceInputMode gst_dreamaudiosource_get_input_mode (GstDreamAudioSource *self)
208 {
209         GstDreamAudioSourceInputMode result;
210         g_return_val_if_fail (GST_IS_DREAMAUDIOSOURCE (self), -1);
211         GST_OBJECT_LOCK (self);
212         result =self->input_mode;
213         GST_OBJECT_UNLOCK (self);
214         return result;
215 }
216
217 gboolean
218 gst_dreamaudiosource_plugin_init (GstPlugin *plugin)
219 {
220         GST_DEBUG_CATEGORY_INIT (dreamaudiosource_debug, "dreamaudiosource", 0, "dreamaudiosource");
221         return gst_element_register (plugin, "dreamaudiosource", GST_RANK_PRIMARY, GST_TYPE_DREAMAUDIOSOURCE);
222 }
223
224 static void
225 gst_dreamaudiosource_init (GstDreamAudioSource * self)
226 {
227         self->encoder = NULL;
228         self->buffers_list = NULL;
229         self->descriptors_available = 0;
230         self->input_mode = DEFAULT_INPUT_MODE;
231
232         g_mutex_init (&self->mutex);
233         READ_SOCKET (self) = -1;
234         WRITE_SOCKET (self) = -1;
235
236         gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
237         gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
238
239         self->encoder = malloc(sizeof(EncoderInfo));
240
241         if(!self->encoder) {
242                 GST_ERROR_OBJECT(self,"out of space");
243                 return;
244         }
245
246         char fn_buf[32];
247         sprintf(fn_buf, "/dev/aenc%d", 0);
248         self->encoder->fd = open(fn_buf, O_RDWR | O_SYNC);
249         if(self->encoder->fd <= 0) {
250                 GST_ERROR_OBJECT(self,"cannot open device %s (%s)", fn_buf, strerror(errno));
251                 free(self->encoder);
252                 self->encoder = NULL;
253                 return;
254         }
255
256         int flags = fcntl(self->encoder->fd, F_GETFL, 0);
257         fcntl(self->encoder->fd, F_SETFL, flags | O_NONBLOCK);
258
259         self->encoder->buffer = malloc(ABUFSIZE);
260         if(!self->encoder->buffer) {
261                 GST_ERROR_OBJECT(self,"cannot alloc buffer");
262                 return;
263         }
264
265         self->encoder->cdb = (unsigned char *)mmap(0, AMMAPSIZE, PROT_READ, MAP_PRIVATE, self->encoder->fd, 0);
266         if(!self->encoder->cdb || self->encoder->cdb == MAP_FAILED) {
267                 GST_ERROR_OBJECT(self,"cannot mmap cdb: %s (%d)", strerror(errno));
268                 self->encoder->cdb = NULL;
269                 return;
270         }
271
272 #ifdef PROVIDE_CLOCK
273         self->encoder_clock = gst_dreamsource_clock_new ("GstDreamAudioSourceClock", self->encoder->fd);
274         GST_OBJECT_FLAG_SET (self, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
275 #endif
276
277 #ifdef dump
278         self->dumpfd = open("/media/hdd/movie/dreamaudiosource.dump", O_WRONLY | O_CREAT | O_TRUNC);
279         GST_DEBUG_OBJECT (self, "dumpfd = %i (%s)", self->dumpfd, (self->dumpfd > 0) ? "OK" : strerror(errno));
280 #endif
281 }
282
283 static void
284 gst_dreamaudiosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
285 {
286         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (object);
287
288         switch (prop_id) {
289                 case ARG_BITRATE:
290                         gst_dreamaudiosource_set_bitrate(self, g_value_get_int (value));
291                         break;
292                 case ARG_INPUT_MODE:
293                              gst_dreamaudiosource_set_input_mode (self, g_value_get_enum (value));
294                         break;
295                 default:
296                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
297                         break;
298         }
299 }
300
301 static void
302 gst_dreamaudiosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
303 {
304         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (object);
305
306         switch (prop_id) {
307                 case ARG_BITRATE:
308                         g_value_set_int (value, self->audio_info.bitrate/1000);
309                         break;
310                 case ARG_INPUT_MODE:
311                         g_value_set_enum (value, gst_dreamaudiosource_get_input_mode (self));
312                         break;
313                 default:
314                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315                         break;
316         }
317 }
318
319 static GstCaps *
320 gst_dreamaudiosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
321 {
322         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
323         GstPadTemplate *pad_template;
324         GstCaps *caps;
325
326         pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS(self), "src");
327         g_return_val_if_fail (pad_template != NULL, NULL);
328
329         if (self->encoder == NULL) {
330                 GST_DEBUG_OBJECT (self, "encoder not opened -> use template caps");
331                 caps = gst_pad_template_get_caps (pad_template);
332         }
333         else
334         {
335                 caps = gst_caps_make_writable(gst_pad_template_get_caps (pad_template));
336         }
337
338         GST_DEBUG_OBJECT (self, "return caps %" GST_PTR_FORMAT, caps);
339         return caps;
340 }
341
342 static gboolean gst_dreamaudiosource_unlock (GstBaseSrc * bsrc)
343 {
344         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
345         GST_DEBUG_OBJECT (self, "stop creating buffers");
346         SEND_COMMAND (self, CONTROL_STOP);
347         return TRUE;
348 }
349
350 static void
351 gst_dreamaudiosource_free_buffer (struct _bufferdebug * bufferdebug)
352 {
353         GST_OBJECT_LOCK (bufferdebug->self);
354         GList *list = g_list_first (bufferdebug->self->buffers_list);
355         int count = 0;
356         while (list) {
357                 GST_TRACE_OBJECT (bufferdebug->self, "buffers_list[%i] = %" GST_PTR_FORMAT "", count, list->data);
358                 count++;
359                 list = g_list_next (list);
360         }
361         bufferdebug->self->buffers_list = g_list_remove(g_list_first (bufferdebug->self->buffers_list), bufferdebug->buffer);
362         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));
363         GST_OBJECT_UNLOCK (bufferdebug->self);
364 }
365
366 static GstFlowReturn
367 gst_dreamaudiosource_create (GstPushSrc * psrc, GstBuffer ** outbuf)
368 {
369         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (psrc);
370         EncoderInfo *enc = self->encoder;
371
372         static int dumpoffset;
373
374         GST_LOG_OBJECT (self, "new buffer requested");
375
376         if (!enc) {
377                 GST_WARNING_OBJECT (self, "encoder device not opened!");
378                 return GST_FLOW_ERROR;
379         }
380
381         while (1)
382         {
383                 *outbuf = NULL;
384
385                 if (self->descriptors_available == 0)
386                 {
387                         self->descriptors_count = 0;
388                         struct pollfd rfd[2];
389
390                         rfd[0].fd = enc->fd;
391                         rfd[0].events = POLLIN;
392                         rfd[1].fd = READ_SOCKET (self);
393                         rfd[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
394
395                         int ret = poll(rfd, 2, 200);
396
397                         if (G_UNLIKELY (ret == -1))
398                         {
399                                 GST_ERROR_OBJECT (self, "SELECT ERROR!");
400                                 return GST_FLOW_ERROR;
401                         }
402                         else if ( ret == 0 )
403                         {
404                                 GST_LOG_OBJECT (self, "SELECT TIMEOUT");
405                                 //!!! TODO generate dummy payload
406                                 *outbuf = gst_buffer_new();
407                         }
408                         else if ( G_UNLIKELY (rfd[1].revents) )
409                         {
410                                 char command;
411                                 READ_COMMAND (self, command, ret);
412                                 if (command == CONTROL_STOP)
413                                 {
414                                         GST_LOG_OBJECT (self, "CONTROL_STOP!");
415                                         return GST_FLOW_FLUSHING;
416                                 }
417                         }
418                         else if ( G_LIKELY(rfd[0].revents & POLLIN) )
419                         {
420                                 int rlen = read(enc->fd, enc->buffer, ABUFSIZE);
421                                 if (rlen <= 0 || rlen % ABDSIZE ) {
422                                         if ( errno == 512 )
423                                                 return GST_FLOW_FLUSHING;
424                                         GST_WARNING_OBJECT (self, "read error %s (%i)", strerror(errno), errno);
425                                         return GST_FLOW_ERROR;
426                                 }
427                                 self->descriptors_available = rlen / ABDSIZE;
428                                 GST_LOG_OBJECT (self, "encoder buffer was empty, %d descriptors available", self->descriptors_available);
429                         }
430                 }
431
432                 while (self->descriptors_count < self->descriptors_available) {
433                         off_t offset = self->descriptors_count * ABDSIZE;
434                         AudioBufferDescriptor *desc = (AudioBufferDescriptor*)(&enc->buffer[offset]);
435
436                         uint32_t f = desc->stCommon.uiFlags;
437
438                         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);
439
440                         if (f & CDB_FLAG_METADATA) {
441                                 GST_LOG_OBJECT (self, "CDB_FLAG_METADATA... skip outdated packet");
442                                 self->descriptors_count = self->descriptors_available;
443                                 continue;
444                         }
445
446                         struct _bufferdebug * bdg = NULL;
447                         GDestroyNotify buffer_free_func = NULL;
448                         if ( gst_debug_category_get_threshold (dreamaudiosource_debug) >= GST_LEVEL_TRACE)
449                         {
450                                 bdg = malloc(sizeof(struct _bufferdebug));
451                                 buffer_free_func = (GDestroyNotify) gst_dreamaudiosource_free_buffer;
452                         }
453
454                         *outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, enc->cdb, AMMAPSIZE, desc->stCommon.uiOffset, desc->stCommon.uiLength, bdg, buffer_free_func);
455
456                         if (bdg)
457                         {
458                                 bdg->self = self;
459                                 bdg->buffer = *outbuf;
460                                 self->buffers_list = g_list_append(self->buffers_list, *outbuf);
461                         }
462
463                         if (f & CDB_FLAG_PTS_VALID)
464                         {
465                                 if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
466                                 {
467                                         if (self->dreamvideosrc)
468                                         {
469                                                 g_mutex_lock (&self->mutex);
470                                                 guint64 videosource_base_pts;
471                                                 g_signal_emit_by_name(self->dreamvideosrc, "get-base-pts", &videosource_base_pts);
472                                                 if (videosource_base_pts != GST_CLOCK_TIME_NONE)
473                                                 {
474                                                         GST_DEBUG_OBJECT (self, "use DREAMVIDEOSOURCE's base_pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (videosource_base_pts) );
475                                                         self->base_pts = videosource_base_pts;
476                                                 }
477                                                 g_mutex_unlock (&self->mutex);
478                                         }
479                                         else
480                                         {
481                                                 self->base_pts = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
482                                                 GST_DEBUG_OBJECT (self, "use mpeg stream pts as base_pts=%" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
483                                         }
484                                 }
485                                 GstClockTime buffer_time = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
486                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_time > self->base_pts )
487                                 {
488                                         buffer_time -= self->base_pts;
489                                         GST_BUFFER_PTS(*outbuf) = buffer_time;
490                                         GST_BUFFER_DTS(*outbuf) = buffer_time;
491                                 }
492                                 if (bdg)
493                                         bdg->buffer_pts = buffer_time;
494                         }
495
496 #ifdef dump
497                         int wret = write(self->dumpfd, (unsigned char*)(enc->cdb + desc->stCommon.uiOffset), desc->stCommon.uiLength);
498                         dumpoffset += wret;
499                         GST_LOG_OBJECT (self, "read %"G_GSIZE_FORMAT" dumped %i total 0x%08X", desc->stCommon.uiLength, wret, dumpoffset );
500 #endif
501                         self->descriptors_count++;
502
503                         break;
504                 }
505
506                 if (self->descriptors_count == self->descriptors_available) {
507                         GST_LOG_OBJECT (self, "self->descriptors_count == self->descriptors_available -> release %i consumed descriptors", self->descriptors_count);
508                         /* release consumed descs */
509                         if (write(enc->fd, &self->descriptors_count, sizeof(self->descriptors_count)) != sizeof(self->descriptors_count)) {
510                                 GST_WARNING_OBJECT (self, "release consumed descs write error!");
511                                 return GST_FLOW_ERROR;
512                         }
513                         self->descriptors_available = 0;
514                 }
515
516                 if (*outbuf)
517                 {
518                         GST_DEBUG_OBJECT (self, "pushing %" GST_PTR_FORMAT "", *outbuf );
519                         return GST_FLOW_OK;
520                 }
521         }
522
523         return GST_FLOW_ERROR;
524 }
525
526 static GstStateChangeReturn gst_dreamaudiosource_change_state (GstElement * element, GstStateChange transition)
527 {
528         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (element);
529         GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS;
530         int ret;
531         switch (transition) {
532                 case GST_STATE_CHANGE_NULL_TO_READY:
533                 {
534                         if (!(self->encoder && self->encoder->cdb))
535                                 return GST_STATE_CHANGE_FAILURE;
536                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_NULL_TO_READY");
537                         break;
538                 }
539                 case GST_STATE_CHANGE_READY_TO_PAUSED:
540                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
541 #ifdef PROVIDE_CLOCK
542                         gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->encoder_clock, TRUE));
543 #endif
544                         break;
545                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
546                         g_mutex_lock (&self->mutex);
547                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
548                         self->base_pts = GST_CLOCK_TIME_NONE;
549                         ret = ioctl(self->encoder->fd, AENC_START);
550                         if ( ret != 0 )
551                                 goto fail;
552                         self->descriptors_available = 0;
553                         CLEAR_COMMAND (self);
554                         GST_INFO_OBJECT (self, "started encoder!");
555                         g_mutex_unlock (&self->mutex);
556                         break;
557                 default:
558                         break;
559         }
560         GST_OBJECT_UNLOCK (self);
561         if (GST_ELEMENT_CLASS (parent_class)->change_state)
562                 sret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
563
564         switch (transition) {
565                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
566                         g_mutex_lock (&self->mutex);
567                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED self->descriptors_count=%i self->descriptors_available=%i", self->descriptors_count, self->descriptors_available);
568                         while (self->descriptors_count < self->descriptors_available)
569                         {
570                                 GST_LOG_OBJECT (self, "flushing self->descriptors_count=%i");
571                                 self->descriptors_count++;
572                         }
573                         if (self->descriptors_count)
574                                 write(self->encoder->fd, &self->descriptors_count, sizeof(self->descriptors_count));
575                         ret = ioctl(self->encoder->fd, AENC_STOP);
576                         if ( ret != 0 )
577                                 goto fail;
578 #ifdef PROVIDE_CLOCK
579                         gst_clock_set_master (self->encoder_clock, NULL);
580 #endif
581                         GST_INFO_OBJECT (self, "stopped encoder!");
582                         g_mutex_unlock (&self->mutex);
583                         break;
584                 case GST_STATE_CHANGE_PAUSED_TO_READY:
585                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PAUSED_TO_READY");
586 #ifdef PROVIDE_CLOCK
587                         gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), self->encoder_clock));
588 #endif
589                         break;
590                 default:
591                         break;
592         }
593         return sret;
594 fail:
595         GST_ERROR_OBJECT(self,"can't perform encoder ioctl!");
596         g_mutex_unlock (&self->mutex);
597         return GST_STATE_CHANGE_FAILURE;
598 }
599
600 static gboolean
601 gst_dreamaudiosource_start (GstBaseSrc * bsrc)
602 {
603         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
604         self->dreamvideosrc = gst_bin_get_by_name_recurse_up(GST_BIN(GST_ELEMENT_PARENT(self)), "dreamvideosource0");
605
606         int control_sock[2];
607         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
608         {
609                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM);
610                 return FALSE;
611         }
612         READ_SOCKET (self) = control_sock[0];
613         WRITE_SOCKET (self) = control_sock[1];
614         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
615         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
616
617         GST_DEBUG_OBJECT (self, "started. reference to dreamvideosource=%" GST_PTR_FORMAT "", self->dreamvideosrc);
618         return TRUE;
619 }
620
621 static gboolean
622 gst_dreamaudiosource_stop (GstBaseSrc * bsrc)
623 {
624         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (bsrc);
625         if (self->dreamvideosrc)
626                 gst_object_unref(self->dreamvideosrc);
627         close (READ_SOCKET (self));
628         close (WRITE_SOCKET (self));
629         READ_SOCKET (self) = -1;
630         WRITE_SOCKET (self) = -1;
631         GST_DEBUG_OBJECT (self, "stop");
632         return TRUE;
633 }
634
635 static void
636 gst_dreamaudiosource_dispose (GObject * gobject)
637 {
638         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (gobject);
639         if (self->encoder) {
640                 if (self->encoder->buffer)
641                         free(self->encoder->buffer);
642                 if (self->encoder->cdb)
643                         munmap(self->encoder->cdb, AMMAPSIZE);
644                 if (self->encoder->fd)
645                         close(self->encoder->fd);
646                 free(self->encoder);
647         }
648 #ifdef PROVIDE_CLOCK
649         if (self->encoder_clock) {
650                 gst_object_unref (self->encoder_clock);
651                 self->encoder_clock = NULL;
652         }
653 #endif
654 #ifdef dump
655         close(self->dumpfd);
656 #endif
657         g_list_free(self->buffers_list);
658         g_mutex_clear (&self->mutex);
659         GST_DEBUG_OBJECT (self, "disposed");
660         G_OBJECT_CLASS (parent_class)->dispose (gobject);
661 }
662
663 #ifdef PROVIDE_CLOCK
664 static GstClock *gst_dreamaudiosource_provide_clock (GstElement * element)
665 {
666         GstDreamAudioSource *self = GST_DREAMAUDIOSOURCE (element);
667
668         if (!self->encoder || self->encoder->fd < 0)
669         {
670                 GST_DEBUG_OBJECT (self, "encoder device not started, can't provide clock!");
671                 return NULL;
672         }
673
674         return GST_CLOCK_CAST (gst_object_ref (self->encoder_clock));
675 }
676
677 #endif
678