Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / sys / v4l2 / gstv4l2radio.c
1 /* GStreamer v4l2 radio tuner element
2  * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
3  *
4  * gstv4l2radio.c - V4L2 radio tuner element
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:element-v4l2radio
24  *
25  * v4l2radio can be used to control radio device
26  * and to tune it to different radiostations.
27  *
28  * <refsect2>
29  * <title>Example launch lines</title>
30  * |[
31  * gst-launch v4l2radio device=/dev/radio0 frequency=101200000
32  * gst-launch alsasrc device=hw:1 ! audioconvert ! audioresample ! alsasink
33  * ]|
34  * First pipeline tunes the radio device /dev/radio0 to station 101.2 MHz,
35  * second pipeline connects digital audio out (hw:1) to default sound card.
36  * </refsect2>
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include <string.h>
44
45 #include "gst/gst-i18n-plugin.h"
46
47 #include "gstv4l2tuner.h"
48 #include "gstv4l2radio.h"
49 #include "v4l2_calls.h"
50
51 GST_DEBUG_CATEGORY_STATIC (v4l2radio_debug);
52 #define GST_CAT_DEFAULT v4l2radio_debug
53
54 #define DEFAULT_PROP_DEVICE "/dev/radio0"
55 #define MIN_FREQUENCY            87500000
56 #define DEFAULT_FREQUENCY       100000000
57 #define MAX_FREQUENCY           108000000
58
59 enum
60 {
61   ARG_0,
62   ARG_DEVICE,
63   ARG_FREQUENCY
64 };
65
66 static gboolean
67 gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
68 {
69   int res;
70   struct v4l2_tuner vtun;
71   struct v4l2_capability vc;
72   GstV4l2TunerChannel *v4l2channel;
73   GstTunerChannel *channel;
74
75   GstElement *e;
76
77   GstV4l2Object *v4l2object;
78
79   e = GST_ELEMENT (radio);
80   v4l2object = radio->v4l2object;
81
82   GST_DEBUG_OBJECT (e, "getting audio enumeration");
83   GST_V4L2_CHECK_OPEN (v4l2object);
84
85   GST_DEBUG_OBJECT (e, "  audio input");
86
87   memset (&vc, 0, sizeof (vc));
88
89   res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc);
90   if (res < 0)
91     goto caps_failed;
92
93   if (!(vc.capabilities & V4L2_CAP_TUNER))
94     goto not_a_tuner;
95
96   /* getting audio input */
97   memset (&vtun, 0, sizeof (vtun));
98   vtun.index = 0;
99
100   res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun);
101   if (res < 0)
102     goto tuner_failed;
103
104   GST_LOG_OBJECT (e, "   index:     %d", vtun.index);
105   GST_LOG_OBJECT (e, "   name:      '%s'", vtun.name);
106   GST_LOG_OBJECT (e, "   type:      %016x", (guint) vtun.type);
107   GST_LOG_OBJECT (e, "   caps:      %016x", (guint) vtun.capability);
108   GST_LOG_OBJECT (e, "   rlow:      %016x", (guint) vtun.rangelow);
109   GST_LOG_OBJECT (e, "   rhigh:     %016x", (guint) vtun.rangehigh);
110   GST_LOG_OBJECT (e, "   audmode:   %016x", (guint) vtun.audmode);
111
112   v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
113   channel = GST_TUNER_CHANNEL (v4l2channel);
114   channel->label = g_strdup ((const gchar *) vtun.name);
115   channel->flags = GST_TUNER_CHANNEL_FREQUENCY | GST_TUNER_CHANNEL_AUDIO;
116   v4l2channel->index = 0;
117   v4l2channel->tuner = 0;
118
119   channel->freq_multiplicator =
120       62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
121   channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
122   channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
123   channel->min_signal = 0;
124   channel->max_signal = 0xffff;
125
126   v4l2object->channels =
127       g_list_prepend (v4l2object->channels, (gpointer) channel);
128
129   v4l2object->channels = g_list_reverse (v4l2object->channels);
130
131   GST_DEBUG_OBJECT (e, "done");
132   return TRUE;
133
134   /* ERRORS */
135 tuner_failed:
136   {
137     GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
138         (_("Failed to get settings of tuner %d on device '%s'."),
139             vtun.index, v4l2object->videodev), GST_ERROR_SYSTEM);
140     return FALSE;
141   }
142 caps_failed:
143   {
144     GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
145         (_("Error getting capabilities for device '%s'."),
146             v4l2object->videodev), GST_ERROR_SYSTEM);
147     return FALSE;
148   }
149 not_a_tuner:
150   {
151     GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
152         (_("Device '%s' is not a tuner."),
153             v4l2object->videodev), GST_ERROR_SYSTEM);
154     return FALSE;
155   }
156 }
157
158 static gboolean
159 gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input)
160 {
161   GST_DEBUG_OBJECT (v4l2object->element, "trying to get radio input");
162
163   if (!GST_V4L2_IS_OPEN (v4l2object))
164     return FALSE;
165
166   if (!v4l2object->channels)
167     goto input_failed;
168
169   *input = 0;
170
171   GST_DEBUG_OBJECT (v4l2object->element, "input: %d", 0);
172
173   return TRUE;
174
175   /* ERRORS */
176 input_failed:
177   {
178     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
179         (_("Failed to get radio input on device '%s'. "),
180             v4l2object->videodev), GST_ERROR_SYSTEM);
181     return FALSE;
182   }
183 }
184
185 static gboolean
186 gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input)
187 {
188   GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
189
190   if (!GST_V4L2_IS_OPEN (v4l2object))
191     return FALSE;
192
193   if (!v4l2object->channels)
194     goto input_failed;
195
196   return TRUE;
197
198   /* ERRORS */
199 input_failed:
200   {
201     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
202         (_("Failed to set input %d on device %s."),
203             input, v4l2object->videodev), GST_ERROR_SYSTEM);
204     return FALSE;
205   }
206 }
207
208 static gboolean
209 gst_v4l2radio_set_mute_on (GstV4l2Radio * radio, gboolean on)
210 {
211   gint res;
212   struct v4l2_control vctrl;
213
214   GST_DEBUG_OBJECT (radio, "setting current tuner mute state: %d", on);
215
216   if (!GST_V4L2_IS_OPEN (radio->v4l2object))
217     return FALSE;
218
219   memset (&vctrl, 0, sizeof (vctrl));
220   vctrl.id = V4L2_CID_AUDIO_MUTE;
221   vctrl.value = on;
222
223   GST_DEBUG_OBJECT (radio, "radio fd: %d", radio->v4l2object->video_fd);
224
225   res = ioctl (radio->v4l2object->video_fd, VIDIOC_S_CTRL, &vctrl);
226   GST_DEBUG_OBJECT (radio, "mute state change result: %d", res);
227   if (res < 0)
228     goto freq_failed;
229
230   return TRUE;
231
232   /* ERRORS */
233 freq_failed:
234   {
235     GST_ELEMENT_WARNING (radio, RESOURCE, SETTINGS,
236         (_("Failed to change mute state for device '%s'."),
237             radio->v4l2object->videodev), GST_ERROR_SYSTEM);
238     return FALSE;
239   }
240 }
241
242 static gboolean
243 gst_v4l2radio_set_mute (GstV4l2Radio * radio)
244 {
245   return gst_v4l2radio_set_mute_on (radio, TRUE);
246 }
247
248 static gboolean
249 gst_v4l2radio_set_unmute (GstV4l2Radio * radio)
250 {
251   return gst_v4l2radio_set_mute_on (radio, FALSE);
252 }
253
254 GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2RadioClass, gst_v4l2radio);
255 GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio);
256
257 static void gst_v4l2radio_uri_handler_init (gpointer g_iface,
258     gpointer iface_data);
259
260 static gboolean
261 gst_v4l2radio_interface_supported (GstImplementsInterface * iface,
262     GType iface_type)
263 {
264   if (iface_type == GST_TYPE_TUNER)
265     return TRUE;
266   else
267     return FALSE;
268 }
269
270 static void
271 gst_v4l2radio_implements_interface_init (GstImplementsInterfaceClass * iface)
272 {
273   iface->supported = gst_v4l2radio_interface_supported;
274 }
275
276 static void
277 gst_v4l2radio_tuner_interface_reinit (GstTunerClass * iface)
278 {
279   gst_v4l2radio_tuner_interface_init (iface);
280 }
281
282 static void
283 gst_v4l2radio_interfaces (GType type)
284 {
285   static const GInterfaceInfo urihandler_info = {
286     (GInterfaceInitFunc) gst_v4l2radio_uri_handler_init,
287     NULL,
288     NULL
289   };
290
291   static const GInterfaceInfo implements_interface_info = {
292     (GInterfaceInitFunc) gst_v4l2radio_implements_interface_init,
293     NULL,
294     NULL,
295   };
296
297   static const GInterfaceInfo propertyprobe_info = {
298     (GInterfaceInitFunc) gst_v4l2radio_property_probe_interface_init,
299     NULL,
300     NULL,
301   };
302
303   static const GInterfaceInfo tuner_interface_info = {
304     (GInterfaceInitFunc) gst_v4l2radio_tuner_interface_reinit,
305     NULL,
306     NULL,
307   };
308
309   g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
310   g_type_add_interface_static (type,
311       GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info);
312
313   g_type_add_interface_static (type, GST_TYPE_TUNER, &tuner_interface_info);
314
315   g_type_add_interface_static (type,
316       GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
317 }
318
319 GST_BOILERPLATE_FULL (GstV4l2Radio, gst_v4l2radio, GstElement, GST_TYPE_ELEMENT,
320     gst_v4l2radio_interfaces);
321
322 static void gst_v4l2radio_set_property (GObject * object, guint prop_id,
323     const GValue * value, GParamSpec * pspec);
324 static void gst_v4l2radio_get_property (GObject * object, guint prop_id,
325     GValue * value, GParamSpec * pspec);
326 static void gst_v4l2radio_finalize (GstV4l2Radio * radio);
327 static void gst_v4l2radio_dispose (GObject * object);
328 static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element,
329     GstStateChange transition);
330
331 static void
332 gst_v4l2radio_base_init (gpointer gclass)
333 {
334   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass);
335   GstV4l2RadioClass *gstv4l2radio_class = GST_V4L2RADIO_CLASS (gclass);
336
337   GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0,
338       "V4l2 radio element");
339
340   gstv4l2radio_class->v4l2_class_devices = NULL;
341
342   gst_element_class_set_details_simple (gstelement_class,
343       "Radio (video4linux2) Tuner",
344       "Tuner",
345       "Controls a Video4Linux2 radio device",
346       "Alexey Chernov <4ernov@gmail.com>");
347 }
348
349 static void
350 gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
351 {
352   GObjectClass *gobject_class;
353   GstElementClass *gstelement_class;
354
355   gobject_class = (GObjectClass *) klass;
356   gstelement_class = (GstElementClass *) klass;
357
358   gobject_class->set_property = gst_v4l2radio_set_property;
359   gobject_class->get_property = gst_v4l2radio_get_property;
360
361   g_object_class_install_property (gobject_class, ARG_DEVICE,
362       g_param_spec_string ("device", "Radio device location",
363           "Video4Linux2 radio device location",
364           DEFAULT_PROP_DEVICE, G_PARAM_READWRITE));
365
366   g_object_class_install_property (gobject_class, ARG_FREQUENCY,
367       g_param_spec_int ("frequency", "Station frequency",
368           "Station frequency in Hz",
369           MIN_FREQUENCY, MAX_FREQUENCY, DEFAULT_FREQUENCY, G_PARAM_READWRITE));
370
371   gobject_class->dispose = gst_v4l2radio_dispose;
372   gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize;
373
374   gstelement_class->change_state =
375       GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state);
376
377 }
378
379 static void
380 gst_v4l2radio_init (GstV4l2Radio * filter, GstV4l2RadioClass * gclass)
381 {
382   filter->v4l2object = gst_v4l2_object_new (GST_ELEMENT (filter),
383       V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE,
384       gst_v4l2radio_get_input, gst_v4l2radio_set_input, NULL);
385
386   filter->v4l2object->frequency = DEFAULT_FREQUENCY;
387   g_free (filter->v4l2object->videodev);
388   filter->v4l2object->videodev = g_strdup (DEFAULT_PROP_DEVICE);
389 }
390
391 static void
392 gst_v4l2radio_dispose (GObject * object)
393 {
394   GstV4l2Radio *radio = GST_V4L2RADIO (object);
395   gst_v4l2_close (radio->v4l2object);
396   G_OBJECT_CLASS (parent_class)->dispose (object);
397 }
398
399 static void
400 gst_v4l2radio_finalize (GstV4l2Radio * radio)
401 {
402   gst_v4l2_object_destroy (radio->v4l2object);
403   G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (radio));
404 }
405
406 static gboolean
407 gst_v4l2radio_open (GstV4l2Radio * radio)
408 {
409   GstV4l2Object *v4l2object;
410
411   v4l2object = radio->v4l2object;
412   if (gst_v4l2_open (v4l2object))
413     return gst_v4l2radio_fill_channel_list (radio);
414   else
415     return FALSE;
416 }
417
418 static void
419 gst_v4l2radio_set_defaults (GstV4l2Radio * radio)
420 {
421   GstV4l2Object *v4l2object;
422   GstTunerChannel *channel = NULL;
423   GstTuner *tuner;
424
425   v4l2object = radio->v4l2object;
426
427   if (!GST_IS_TUNER (v4l2object->element))
428     return;
429
430   tuner = GST_TUNER (v4l2object->element);
431
432   if (v4l2object->channel)
433     channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
434   if (channel) {
435     gst_tuner_set_channel (tuner, channel);
436   } else {
437     channel =
438         GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
439             (v4l2object->element)));
440     if (channel) {
441       g_free (v4l2object->channel);
442       v4l2object->channel = g_strdup (channel->label);
443       gst_tuner_channel_changed (tuner, channel);
444     }
445   }
446
447   if (channel
448       && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
449     if (v4l2object->frequency != 0) {
450       gst_tuner_set_frequency (tuner, channel, v4l2object->frequency);
451     } else {
452       v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
453       if (v4l2object->frequency == 0) {
454         /* guess */
455         gst_tuner_set_frequency (tuner, channel, MIN_FREQUENCY);
456       } else {
457       }
458     }
459   }
460 }
461
462 static gboolean
463 gst_v4l2radio_start (GstV4l2Radio * radio)
464 {
465   if (!gst_v4l2radio_open (radio))
466     return FALSE;
467
468   gst_v4l2radio_set_defaults (radio);
469
470   return TRUE;
471 }
472
473 static gboolean
474 gst_v4l2radio_stop (GstV4l2Radio * radio)
475 {
476   if (!gst_v4l2_object_stop (radio->v4l2object))
477     return FALSE;
478
479   return TRUE;
480 }
481
482 static GstStateChangeReturn
483 gst_v4l2radio_change_state (GstElement * element, GstStateChange transition)
484 {
485   GstV4l2Radio *radio;
486   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
487
488   radio = GST_V4L2RADIO (element);
489   switch (transition) {
490     case GST_STATE_CHANGE_NULL_TO_READY:
491       /*start radio */
492       if (!gst_v4l2radio_start (radio))
493         ret = GST_STATE_CHANGE_FAILURE;
494       break;
495     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
496       /*unmute radio */
497       if (!gst_v4l2radio_set_unmute (radio))
498         ret = GST_STATE_CHANGE_FAILURE;
499       break;
500     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
501       /*mute radio */
502       if (!gst_v4l2radio_set_mute (radio))
503         ret = GST_STATE_CHANGE_FAILURE;
504       break;
505     case GST_STATE_CHANGE_READY_TO_NULL:
506       /*stop radio */
507       if (!gst_v4l2radio_stop (radio))
508         ret = GST_STATE_CHANGE_FAILURE;
509       break;
510     default:
511       break;
512   }
513
514   return ret;
515 }
516
517 static void
518 gst_v4l2radio_set_property (GObject * object, guint prop_id,
519     const GValue * value, GParamSpec * pspec)
520 {
521   GstV4l2Radio *radio = GST_V4L2RADIO (object);
522   gint frequency;
523   switch (prop_id) {
524     case ARG_DEVICE:
525       g_free (radio->v4l2object->videodev);
526       radio->v4l2object->videodev =
527           g_strdup ((gchar *) g_value_get_string (value));
528       break;
529     case ARG_FREQUENCY:
530       frequency = g_value_get_int (value);
531       if (frequency >= MIN_FREQUENCY && frequency <= MAX_FREQUENCY) {
532         radio->v4l2object->frequency = frequency;
533         gst_v4l2_set_frequency (radio->v4l2object, 0,
534             radio->v4l2object->frequency);
535       }
536       break;
537     default:
538       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
539       break;
540   }
541 }
542
543 static void
544 gst_v4l2radio_get_property (GObject * object, guint prop_id,
545     GValue * value, GParamSpec * pspec)
546 {
547   GstV4l2Radio *radio = GST_V4L2RADIO (object);
548
549   switch (prop_id) {
550     case ARG_DEVICE:
551       g_value_set_string (value, radio->v4l2object->videodev);
552       break;
553     case ARG_FREQUENCY:
554       if (gst_v4l2_get_frequency (radio->v4l2object,
555               0, &(radio->v4l2object->frequency)))
556         g_value_set_int (value, radio->v4l2object->frequency);
557       break;
558     default:
559       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
560       break;
561   }
562 }
563
564 /* GstURIHandler interface */
565 static GstURIType
566 gst_v4l2radio_uri_get_type (void)
567 {
568   return GST_URI_SRC;
569 }
570
571 static gchar **
572 gst_v4l2radio_uri_get_protocols (void)
573 {
574   static gchar *protocols[] = { (char *) "radio", NULL };
575   return protocols;
576 }
577
578 static const gchar *
579 gst_v4l2radio_uri_get_uri (GstURIHandler * handler)
580 {
581   GstV4l2Radio *radio = GST_V4L2RADIO (handler);
582
583   if (radio->v4l2object->videodev != NULL) {
584     if (gst_v4l2_get_frequency (radio->v4l2object,
585             0, &(radio->v4l2object->frequency))) {
586       gchar uri[20];
587       gchar freq[6];
588       g_ascii_formatd (freq, 6, "%4.1f", radio->v4l2object->frequency / 1e6);
589       g_snprintf (uri, sizeof (uri), "radio://%s", freq);
590       return g_intern_string (uri);
591     }
592   }
593
594   return "radio://";
595 }
596
597 static gboolean
598 gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri)
599 {
600   GstV4l2Radio *radio = GST_V4L2RADIO (handler);
601   gdouble dfreq;
602   gint ifreq;
603   const gchar *freq;
604   gchar *end;
605
606   if (strcmp (uri, "radio://") != 0) {
607     freq = uri + 8;
608
609     dfreq = g_ascii_strtod (freq, &end);
610
611     if (errno || strlen (end))
612       goto uri_failed;
613
614     ifreq = dfreq * 1e6;
615     g_object_set (radio, "frequency", ifreq, NULL);
616
617   } else
618     goto uri_failed;
619
620   return TRUE;
621
622 uri_failed:
623   return FALSE;
624 }
625
626 static void
627 gst_v4l2radio_uri_handler_init (gpointer g_iface, gpointer iface_data)
628 {
629   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
630
631   iface->get_type = gst_v4l2radio_uri_get_type;
632   iface->get_protocols = gst_v4l2radio_uri_get_protocols;
633   iface->get_uri = gst_v4l2radio_uri_get_uri;
634   iface->set_uri = gst_v4l2radio_uri_set_uri;
635 }