tinycompresssink: add h/w volume set
[platform/upstream/gst-plugins-tizen.git] / tinycompresssink / src / gsttinycompresssink.c
1 /* GStreamer
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Library General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Library General Public License for more details.
12  *
13  * You should have received a copy of the GNU Library General Public
14  * License along with this library; if not, write to the
15  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
16  * Boston, MA 02110-1301, USA.
17  */
18
19 /**
20  * SECTION:element-tinycompresssink
21  * @title: tinycompresssink
22  *
23  * Render MP3 data in compress device using tinycompress
24  *
25  * ## Example launch line
26  * |[
27  * gst-launch-1.0 filesrc location=sample.mp3 ! mpegaudioparse ! tinycompresssink
28  * ]| test audio rendering in tinycompress
29  *
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "gsttinycompresssink.h"
37 #include <string.h>
38 #include <sys/time.h>
39 #include <stdint.h>
40 #include <unistd.h>
41
42 #include <sound_manager.h>
43 #include <asoundlib.h>
44
45 /* FIXME: This might be configurable (eg. property) */
46 #define ALSA_DEFAULT_CARD "Exynos9110Sound"
47
48 #define COMPRESS_VOL_CTRL "ComprTx0 Volume"
49
50 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
51     GST_PAD_SINK,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS_ANY);
54
55 #define DEFAULT_SYNC TRUE
56 #define DEFAULT_DUMP FALSE
57 #define DEFAULT_CARD 0
58 #define DEFAULT_DEVICE 5
59
60 enum
61 {
62   PROP_0,
63   PROP_DUMP,
64 };
65
66 GST_DEBUG_CATEGORY_STATIC (gst_tinycompress_sink_debug);
67 #define GST_CAT_DEFAULT gst_tinycompress_sink_debug
68 #define gst_tinycompress_sink_parent_class parent_class
69 G_DEFINE_TYPE (GstTinycompressSink, gst_tinycompress_sink, GST_TYPE_BASE_SINK);
70
71 static void gst_tinycompress_sink_set_property (GObject * object, guint prop_id,
72     const GValue * value, GParamSpec * pspec);
73 static void gst_tinycompress_sink_get_property (GObject * object, guint prop_id,
74     GValue * value, GParamSpec * pspec);
75 static void gst_tinycompress_sink_finalize (GObject * object);
76
77 static GstStateChangeReturn gst_tinycompress_sink_change_state (GstElement *
78     element, GstStateChange transition);
79 static GstFlowReturn gst_tinycompress_sink_render (GstBaseSink * bsink,
80     GstBuffer * buffer);
81 static GstCaps *gst_tinycompress_sink_get_caps (GstBaseSink * bsink,
82     GstCaps * filter);
83 static gboolean gst_tinycompress_sink_set_caps (GstBaseSink * bsink,
84     GstCaps * caps);
85 static void gst_tinycompress_sink_get_times (GstBaseSink * bsink,
86     GstBuffer * buf, GstClockTime * start, GstClockTime * end);
87 static gboolean gst_tinycompress_sink_event (GstBaseSink * bsink,
88     GstEvent * event);
89
90 static void
91 _dump_compress_status (GstTinycompressSink * sink, struct compress *compress)
92 {
93   unsigned int avail;
94   unsigned int sampling_rate = 0;
95   unsigned int samples = 0;
96   struct timespec tstamp;
97
98   g_return_if_fail (compress != NULL);
99
100   compress_get_tstamp (compress, &samples, &sampling_rate);
101
102   if (compress_get_hpointer (compress, &avail, &tstamp) != 0) {
103     GST_ERROR_OBJECT (sink, "Error querying timestamp : %s",
104         compress_get_error (compress));
105   } else {
106     GST_DEBUG_OBJECT (sink,
107         "samples:%10d, avail:%7d, DSP played:%4jd.%03jd\n", samples, avail,
108         (intmax_t) (tstamp.tv_sec / sink->t_codec.ch_in),
109         (intmax_t) (tstamp.tv_nsec / sink->t_codec.ch_in) / 1000000);
110   }
111 }
112
113 static gboolean
114 _mixer_control_set_value (GstTinycompressSink * sink, const char *ctl_name,
115     int val)
116 {
117   snd_ctl_t *handle;
118   snd_ctl_elem_value_t *control;
119   snd_ctl_elem_id_t *id;
120   snd_ctl_elem_info_t *info;
121   snd_ctl_elem_type_t type;
122   int ret = 0;
123   int count = 0;
124   int i = 0;
125
126   ret = snd_ctl_open (&handle, ALSA_DEFAULT_CARD, 0);
127   if (ret < 0) {
128     GST_ERROR_OBJECT (sink, "snd_ctl_open error, card: %s: %s",
129         ALSA_DEFAULT_CARD, snd_strerror (ret));
130     return FALSE;
131   }
132
133   snd_ctl_elem_id_alloca (&id);
134   snd_ctl_elem_info_alloca (&info);
135   snd_ctl_elem_value_alloca (&control);
136
137   snd_ctl_elem_id_set_interface (id, SND_CTL_ELEM_IFACE_MIXER);
138   snd_ctl_elem_id_set_name (id, ctl_name);
139
140   snd_ctl_elem_info_set_id (info, id);
141   if (snd_ctl_elem_info (handle, info) < 0) {
142     GST_ERROR_OBJECT (sink, "Cannot find control element: %s", ctl_name);
143     goto close;
144   }
145   snd_ctl_elem_info_get_id (info, id);
146
147   type = snd_ctl_elem_info_get_type (info);
148   count = snd_ctl_elem_info_get_count (info);
149
150   snd_ctl_elem_value_set_id (control, id);
151
152   snd_ctl_elem_read (handle, control);
153
154   switch (type) {
155     case SND_CTL_ELEM_TYPE_BOOLEAN:
156       for (i = 0; i < count; i++)
157         snd_ctl_elem_value_set_boolean (control, i, val);
158       break;
159
160     case SND_CTL_ELEM_TYPE_INTEGER:
161       for (i = 0; i < count; i++)
162         snd_ctl_elem_value_set_integer (control, i, val);
163       break;
164
165     case SND_CTL_ELEM_TYPE_ENUMERATED:
166       for (i = 0; i < count; i++)
167         snd_ctl_elem_value_set_enumerated (control, i, val);
168       break;
169
170     default:
171       GST_WARNING_OBJECT (sink, "unsupported control element type");
172       goto close;
173   }
174
175   snd_ctl_elem_write (handle, control);
176
177   snd_ctl_close (handle);
178
179   GST_INFO_OBJECT (sink, "set mixer(%s) = %d success", ctl_name, val);
180
181   return TRUE;
182
183 close:
184   GST_ERROR_OBJECT (sink, "Error");
185   snd_ctl_close (handle);
186
187   return FALSE;
188 }
189
190 static gboolean
191 gst_tinycompress_set_codec_param (GstTinycompressSink * sink, GstCaps * caps)
192 {
193   GstStructure *structure;
194   gint rate = 0;
195   gint channels = 0;
196
197   g_return_val_if_fail (sink != NULL, FALSE);
198   g_return_val_if_fail (caps != NULL, FALSE);
199
200   structure = gst_caps_get_structure (caps, 0);
201   gst_structure_get_int (structure, "rate", &rate);
202   gst_structure_get_int (structure, "channels", &channels);
203
204   sink->t_codec.id = SND_AUDIOCODEC_MP3;
205   sink->t_codec.ch_in = channels;
206   sink->t_codec.ch_out = channels;
207   sink->t_codec.sample_rate = rate;
208   sink->t_codec.bit_rate = 0;
209   sink->t_codec.rate_control = 0;
210   sink->t_codec.profile = 0;
211   sink->t_codec.level = 0;
212   sink->t_codec.ch_mode = 0;
213   sink->t_codec.format = 0;
214
215   GST_INFO_OBJECT (sink, "t_codec: id(%d), channel(%d), sample_rate(%d)",
216       SND_AUDIOCODEC_MP3, channels, rate);
217
218   return TRUE;
219 }
220
221 static void
222 gst_tinycompress_sink_class_init (GstTinycompressSinkClass * klass)
223 {
224   GObjectClass *gobject_class;
225   GstElementClass *gstelement_class;
226   GstBaseSinkClass *gstbase_sink_class;
227
228   gobject_class = G_OBJECT_CLASS (klass);
229   gstelement_class = GST_ELEMENT_CLASS (klass);
230   gstbase_sink_class = GST_BASE_SINK_CLASS (klass);
231
232   gobject_class->set_property = gst_tinycompress_sink_set_property;
233   gobject_class->get_property = gst_tinycompress_sink_get_property;
234   gobject_class->finalize = gst_tinycompress_sink_finalize;
235
236   g_object_class_install_property (gobject_class, PROP_DUMP,
237       g_param_spec_boolean ("dump", "Dump", "Dump buffer contents to stdout",
238           DEFAULT_DUMP,
239           G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
240           G_PARAM_STATIC_STRINGS));
241
242   gst_element_class_set_static_metadata (gstelement_class,
243       "Tinycompress Sink",
244       "Sink", "Render MP3 data in compress device using tinycompress", "Tizen");
245
246   gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
247
248   gstelement_class->change_state =
249       GST_DEBUG_FUNCPTR (gst_tinycompress_sink_change_state);
250
251   gstbase_sink_class->render = GST_DEBUG_FUNCPTR (gst_tinycompress_sink_render);
252   gstbase_sink_class->get_caps =
253       GST_DEBUG_FUNCPTR (gst_tinycompress_sink_get_caps);
254   gstbase_sink_class->set_caps =
255       GST_DEBUG_FUNCPTR (gst_tinycompress_sink_set_caps);
256   gstbase_sink_class->get_times =
257       GST_DEBUG_FUNCPTR (gst_tinycompress_sink_get_times);
258   gstbase_sink_class->event = GST_DEBUG_FUNCPTR (gst_tinycompress_sink_event);
259 }
260
261 static void
262 _volume_changed_cb (sound_type_e type, unsigned int volume, void *user_data)
263 {
264   GstTinycompressSink *sink = (GstTinycompressSink *) user_data;
265
266   GST_INFO_OBJECT (sink, " type %d, volume %u", type, volume);
267
268   /* FIXME: For now current volume range for media is 0~15,
269      corresponding mixer control range is 0~8192.
270      As level matching will be part of tunning issue in the future,
271      we just set value to level multiplied by 100 which seems to be fine */
272   if (type == SOUND_TYPE_MEDIA)
273     _mixer_control_set_value (sink, COMPRESS_VOL_CTRL, volume * 100);
274 }
275
276 static void
277 gst_tinycompress_sink_init (GstTinycompressSink * sink)
278 {
279   int media_volume = -1;
280
281   sink->dump = DEFAULT_DUMP;
282   sink->card = DEFAULT_CARD;
283   sink->device = DEFAULT_DEVICE;
284   sink->compress_paused = FALSE;
285   sink->volume_cb_id = -1;
286
287   if (sound_manager_get_volume (SOUND_TYPE_MEDIA,
288           &media_volume) != SOUND_MANAGER_ERROR_NONE)
289     GST_ERROR_OBJECT (sink, "failed to get media volume");
290
291   if (sound_manager_add_volume_changed_cb (_volume_changed_cb, sink,
292           &sink->volume_cb_id) != SOUND_MANAGER_ERROR_NONE)
293     GST_ERROR_OBJECT (sink, "failed to add volume changed cb");
294
295   GST_INFO_OBJECT (sink, "Initial media volume was %d, added volume cb %d",
296       media_volume, sink->volume_cb_id);
297
298   _mixer_control_set_value (sink, "ComprTx0 Volume", media_volume * 100);
299 }
300
301 static void
302 gst_tinycompress_sink_finalize (GObject * object)
303 {
304   GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK (object);
305
306   if (sink->volume_cb_id != -1)
307     if (sound_manager_remove_volume_changed_cb (sink->volume_cb_id) !=
308         SOUND_MANAGER_ERROR_NONE)
309       GST_ERROR_OBJECT (sink, "failed to remove volume changed cb (id:%d)",
310           sink->volume_cb_id);
311
312   G_OBJECT_CLASS (parent_class)->finalize (object);
313 }
314
315 static void
316 gst_tinycompress_sink_set_property (GObject * object, guint prop_id,
317     const GValue * value, GParamSpec * pspec)
318 {
319   GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK (object);
320
321   switch (prop_id) {
322     case PROP_DUMP:
323       sink->dump = g_value_get_boolean (value);
324       break;
325
326     default:
327       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328       break;
329   }
330 }
331
332 static void
333 gst_tinycompress_sink_get_property (GObject * object, guint prop_id,
334     GValue * value, GParamSpec * pspec)
335 {
336   GstTinycompressSink *sink;
337
338   sink = GST_TINYCOMPRESS_SINK (object);
339
340   switch (prop_id) {
341     case PROP_DUMP:
342       g_value_set_boolean (value, sink->dump);
343       break;
344
345     default:
346       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
347       break;
348   }
349 }
350
351 static GstFlowReturn
352 gst_tinycompress_sink_render (GstBaseSink * bsink, GstBuffer * buf)
353 {
354   GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK_CAST (bsink);
355   int ret = GST_FLOW_OK;
356   GstMapInfo info;
357
358   g_return_val_if_fail (sink->compress != NULL, FALSE);
359
360   GST_OBJECT_LOCK (sink);
361
362   gst_buffer_map (buf, &info, GST_MAP_READ);
363   if (sink->dump) {
364     gst_util_dump_mem (info.data, info.size);
365   }
366
367   ret = compress_write (sink->compress, info.data, info.size);
368   if (ret != info.size) {
369     GST_ERROR_OBJECT (sink, "Could not write data to device");
370     gst_buffer_unmap (buf, &info);
371     GST_OBJECT_UNLOCK (sink);
372     return GST_FLOW_ERROR;
373   }
374   sink->written += info.size;
375   GST_DEBUG_OBJECT (sink, " >> Wrote %u bytes, accum %u", info.size,
376       sink->written);
377
378   /* FIXEME: needs separate property for control */
379   _dump_compress_status (sink, sink->compress);
380
381   if (!is_compress_running (sink->compress)
382       && sink->written >= sink->start_threashold) {
383     GST_INFO_OBJECT (sink, "Start Now!!!");
384     if (compress_start (sink->compress) != 0) {
385       GST_ERROR_OBJECT (sink, "Could not start!!!");
386     } else {
387       GST_INFO_OBJECT (sink, "Started done!!!");
388       sink->compress_paused = FALSE;
389     }
390   }
391
392   gst_buffer_unmap (buf, &info);
393   GST_OBJECT_UNLOCK (sink);
394
395   return GST_FLOW_OK;
396 }
397
398 static GstCaps *
399 gst_tinycompress_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
400 {
401   GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK (bsink);
402   GstCaps *caps = NULL;
403
404   GST_OBJECT_LOCK (sink);
405   caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
406   GST_OBJECT_UNLOCK (sink);
407
408   GST_INFO_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps);
409
410   if (caps && filter) {
411     GstCaps *intersection =
412         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
413
414     gst_caps_unref (caps);
415     caps = intersection;
416   }
417
418   GST_DEBUG_OBJECT (sink, "result get caps: %" GST_PTR_FORMAT, caps);
419
420   return caps;
421 }
422
423 static gboolean
424 gst_tinycompress_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
425 {
426   GstTinycompressSink *sink;
427
428   sink = GST_TINYCOMPRESS_SINK (bsink);
429   GST_INFO_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
430
431   gst_tinycompress_set_codec_param (sink, caps);
432
433   return TRUE;
434 }
435
436 static void
437 gst_tinycompress_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
438     GstClockTime * start, GstClockTime * end)
439 {
440   /* to check valid buffer based on the start and end time */
441   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
442     *start = GST_BUFFER_TIMESTAMP (buf);
443
444     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
445       *end = *start + GST_BUFFER_DURATION (buf);
446     }
447   }
448 }
449
450 static gboolean
451 gst_tinycompress_resume (GstTinycompressSink * sink)
452 {
453   int ret;
454   g_return_val_if_fail (sink != NULL, FALSE);
455
456   GST_INFO_OBJECT (sink, "gst_tinycompress_resume");
457
458   if (!sink->compress)
459     goto not_opened;
460
461   if (!sink->compress_paused)
462     goto not_paused;
463
464   if (!is_compress_running (sink->compress))
465     goto not_started;
466
467   ret = compress_resume (sink->compress);
468   GST_INFO_OBJECT (sink, "resuming the device, ret=%d", ret);
469   if (ret != 0) {
470     GST_ERROR_OBJECT (sink, "Error %d resuming device\n", ret);
471     return FALSE;
472   }
473
474   sink->compress_paused = FALSE;
475
476   return TRUE;
477
478 not_opened:
479   GST_ERROR_OBJECT (sink, "Error: Tinycompress device is not opened yet!");
480   return FALSE;
481
482 not_paused:
483   GST_ERROR_OBJECT (sink, "Error: Tinycompress device is not paused yet!");
484   return FALSE;
485
486 not_started:
487   GST_ERROR_OBJECT (sink, "Note: Tinycompress device is not started!");
488   return FALSE;
489 }
490
491 static gboolean
492 gst_tinycompress_pause (GstTinycompressSink * sink)
493 {
494   int ret;
495
496   g_return_val_if_fail (sink != NULL, FALSE);
497
498   GST_INFO_OBJECT (sink, "gst_tinycompress_pause");
499
500   if (!sink->compress)
501     goto not_opened;
502
503   if (!is_compress_running (sink->compress))
504     goto not_started;
505
506   ret = compress_pause (sink->compress);
507   GST_INFO_OBJECT (sink, "pausing the device, ret=%d", ret);
508   if (ret != 0) {
509     GST_ERROR_OBJECT (sink, "Error %d pausing device, %s\n", ret,
510         compress_get_error (sink->compress));
511     return FALSE;
512   }
513   sink->compress_paused = TRUE;
514
515   return TRUE;
516
517 not_opened:
518   GST_ERROR_OBJECT (sink, "Error: Tinycompress device is not opened yet!");
519   return TRUE;
520
521 not_started:
522   GST_ERROR_OBJECT (sink, "Note: Tinycompress device is not started!");
523   return TRUE;
524 }
525
526 static gboolean
527 gst_tinycompress_unprepare (GstTinycompressSink * sink)
528 {
529   if (sink->compress)
530     if (compress_stop (sink->compress) != 0)
531       GST_ERROR_OBJECT (sink, "Could not stop device");
532
533   GST_OBJECT_LOCK (sink);
534
535   if (sink->compress)
536     compress_close (sink->compress);
537   sink->compress = NULL;
538
539   GST_INFO_OBJECT (sink, "Compress device %d:%d closed", sink->card,
540       sink->device);
541
542   sink->compress_paused = FALSE;
543   sink->written = 0;
544
545   GST_OBJECT_UNLOCK (sink);
546
547   return TRUE;
548 }
549
550 static gboolean
551 gst_tinycompress_open (GstTinycompressSink * sink)
552 {
553   g_return_val_if_fail (sink != NULL, FALSE);
554
555   GST_INFO_OBJECT (sink, "gst_tinycompress_open");
556
557   sink->t_config.codec = &sink->t_codec;
558
559   GST_OBJECT_LOCK (sink);
560
561   sink->compress =
562       compress_open (sink->card, sink->device, COMPRESS_IN, &sink->t_config);
563   if (!sink->compress) {
564     GST_ERROR_OBJECT (sink, "Unable to open Compress device %d:%d", sink->card,
565         sink->device);
566     goto fail;
567   }
568
569   /* FIXME: need to property, wait for writting */
570   compress_set_max_poll_wait (sink->compress, 3000);
571
572   sink->start_threashold =
573       sink->t_config.fragment_size * sink->t_config.fragments;
574   GST_INFO_OBJECT (sink, "Got fragment_size: %d, fragments :%d",
575       sink->t_config.fragment_size, sink->t_config.fragments);
576   GST_INFO_OBJECT (sink, "buffer size for buffering : %d",
577       sink->start_threashold);
578
579   if (!is_compress_ready (sink->compress)) {
580     GST_ERROR_OBJECT (sink, "ERR: %s\n", compress_get_error (sink->compress));
581     goto fail;
582   }
583
584   GST_INFO_OBJECT (sink, "Compress device %d:%d opened", sink->card,
585       sink->device);
586
587   sink->written = 0;
588
589   GST_OBJECT_UNLOCK (sink);
590
591   return TRUE;
592
593 fail:
594   GST_OBJECT_UNLOCK (sink);
595
596   if (sink->compress) {
597     compress_close (sink->compress);
598     sink->compress = NULL;
599   }
600
601   return FALSE;
602 }
603
604 static GstStateChangeReturn
605 gst_tinycompress_sink_change_state (GstElement * element,
606     GstStateChange transition)
607 {
608   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
609   GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK (element);
610
611   switch (transition) {
612     case GST_STATE_CHANGE_NULL_TO_READY:
613       GST_INFO_OBJECT (sink, "NULL_TO_READY");
614       break;
615
616     case GST_STATE_CHANGE_READY_TO_PAUSED:
617       GST_INFO_OBJECT (sink, "READY_TO_PAUSED");
618       break;
619
620     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
621       GST_INFO_OBJECT (sink, "PAUSED_TO_PLAYING");
622       if (!sink->compress)
623         gst_tinycompress_open (sink);
624       if (sink->compress_paused)
625         gst_tinycompress_resume (sink);
626       break;
627
628     default:
629       break;
630   }
631
632   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
633
634   switch (transition) {
635     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
636       GST_INFO_OBJECT (sink, "PLAYING_TO_PAUSED");
637       gst_tinycompress_pause (sink);
638       break;
639
640     case GST_STATE_CHANGE_PAUSED_TO_READY:
641       GST_INFO_OBJECT (sink, "PAUSED_TO_READY");
642       gst_tinycompress_unprepare (sink);
643       break;
644
645     case GST_STATE_CHANGE_READY_TO_NULL:
646       GST_INFO_OBJECT (sink, "READY_TO_NULL");
647       break;
648
649     default:
650       break;
651   }
652   return ret;
653 }
654
655 static gboolean
656 gst_tinycompress_sink_event (GstBaseSink * bsink, GstEvent * event)
657 {
658   GstTinycompressSink *sink;
659   sink = GST_TINYCOMPRESS_SINK (bsink);
660
661   GST_INFO_OBJECT (sink, "got event (%s)",
662       gst_event_type_get_name (GST_EVENT_TYPE (event)));
663
664   switch (GST_EVENT_TYPE (event)) {
665     case GST_EVENT_EOS:
666       GST_INFO_OBJECT (sink, "get GST_EVENT_EOS event..state is %d",
667           GST_STATE (sink));
668       break;
669
670     default:
671       break;
672   }
673
674   return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
675 }
676
677 static gboolean
678 plugin_init (GstPlugin * plugin)
679 {
680   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "tinycompresssink", 0,
681       "Tinycompress sink plugin");
682
683   return gst_element_register (plugin, "tinycompresssink", GST_RANK_NONE,
684       GST_TYPE_TINYCOMPRESS_SINK);
685 }
686
687 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, tinycompress,
688     "tinycompress plugin library", plugin_init, VERSION, "LGPL",
689     GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)