1 /* GStreamer v4l2 radio tuner element
2 * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
4 * gstv4l2radio.c - V4L2 radio tuner element
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.
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.
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.
23 * SECTION:element-v4l2radio
25 * v4l2radio can be used to control radio device
26 * and to tune it to different radiostations.
29 * <title>Example launch lines</title>
31 * gst-launch v4l2radio device=/dev/radio0 frequency=101200000
32 * gst-launch alsasrc device=hw:1 ! audioconvert ! audioresample ! alsasink
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.
45 #include "gst/gst-i18n-plugin.h"
47 #include "gstv4l2tuner.h"
48 #include "gstv4l2radio.h"
49 #include "v4l2_calls.h"
51 GST_DEBUG_CATEGORY_STATIC (v4l2radio_debug);
52 #define GST_CAT_DEFAULT v4l2radio_debug
54 #define DEFAULT_PROP_DEVICE "/dev/radio0"
55 #define MIN_FREQUENCY 87500000
56 #define DEFAULT_FREQUENCY 100000000
57 #define MAX_FREQUENCY 108000000
67 gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
70 struct v4l2_tuner vtun;
71 struct v4l2_capability vc;
72 GstV4l2TunerChannel *v4l2channel;
73 GstTunerChannel *channel;
77 GstV4l2Object *v4l2object;
79 e = GST_ELEMENT (radio);
80 v4l2object = radio->v4l2object;
82 GST_DEBUG_OBJECT (e, "getting audio enumeration");
83 GST_V4L2_CHECK_OPEN (v4l2object);
85 GST_DEBUG_OBJECT (e, " audio input");
87 memset (&vc, 0, sizeof (vc));
89 res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc);
93 if (!(vc.capabilities & V4L2_CAP_TUNER))
96 /* getting audio input */
97 memset (&vtun, 0, sizeof (vtun));
100 res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun);
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);
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;
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;
126 v4l2object->channels =
127 g_list_prepend (v4l2object->channels, (gpointer) channel);
129 v4l2object->channels = g_list_reverse (v4l2object->channels);
131 GST_DEBUG_OBJECT (e, "done");
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);
144 GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
145 (_("Error getting capabilities for device '%s'."),
146 v4l2object->videodev), GST_ERROR_SYSTEM);
151 GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
152 (_("Device '%s' is not a tuner."),
153 v4l2object->videodev), GST_ERROR_SYSTEM);
159 gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input)
161 GST_DEBUG_OBJECT (v4l2object->element, "trying to get radio input");
163 if (!GST_V4L2_IS_OPEN (v4l2object))
166 if (!v4l2object->channels)
171 GST_DEBUG_OBJECT (v4l2object->element, "input: %d", 0);
178 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
179 (_("Failed to get radio input on device '%s'. "),
180 v4l2object->videodev), GST_ERROR_SYSTEM);
186 gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input)
188 GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
190 if (!GST_V4L2_IS_OPEN (v4l2object))
193 if (!v4l2object->channels)
201 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
202 (_("Failed to set input %d on device %s."),
203 input, v4l2object->videodev), GST_ERROR_SYSTEM);
209 gst_v4l2radio_set_mute_on (GstV4l2Radio * radio, gboolean on)
212 struct v4l2_control vctrl;
214 GST_DEBUG_OBJECT (radio, "setting current tuner mute state: %d", on);
216 if (!GST_V4L2_IS_OPEN (radio->v4l2object))
219 memset (&vctrl, 0, sizeof (vctrl));
220 vctrl.id = V4L2_CID_AUDIO_MUTE;
223 GST_DEBUG_OBJECT (radio, "radio fd: %d", radio->v4l2object->video_fd);
225 res = ioctl (radio->v4l2object->video_fd, VIDIOC_S_CTRL, &vctrl);
226 GST_DEBUG_OBJECT (radio, "mute state change result: %d", res);
235 GST_ELEMENT_WARNING (radio, RESOURCE, SETTINGS,
236 (_("Failed to change mute state for device '%s'."),
237 radio->v4l2object->videodev), GST_ERROR_SYSTEM);
243 gst_v4l2radio_set_mute (GstV4l2Radio * radio)
245 return gst_v4l2radio_set_mute_on (radio, TRUE);
249 gst_v4l2radio_set_unmute (GstV4l2Radio * radio)
251 return gst_v4l2radio_set_mute_on (radio, FALSE);
254 GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2RadioClass, gst_v4l2radio);
255 GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio);
257 static void gst_v4l2radio_uri_handler_init (gpointer g_iface,
258 gpointer iface_data);
261 gst_v4l2radio_interface_supported (GstImplementsInterface * iface,
264 if (iface_type == GST_TYPE_TUNER)
271 gst_v4l2radio_implements_interface_init (GstImplementsInterfaceClass * iface)
273 iface->supported = gst_v4l2radio_interface_supported;
277 gst_v4l2radio_tuner_interface_reinit (GstTunerClass * iface)
279 gst_v4l2radio_tuner_interface_init (iface);
283 gst_v4l2radio_interfaces (GType type)
285 static const GInterfaceInfo urihandler_info = {
286 (GInterfaceInitFunc) gst_v4l2radio_uri_handler_init,
291 static const GInterfaceInfo implements_interface_info = {
292 (GInterfaceInitFunc) gst_v4l2radio_implements_interface_init,
297 static const GInterfaceInfo propertyprobe_info = {
298 (GInterfaceInitFunc) gst_v4l2radio_property_probe_interface_init,
303 static const GInterfaceInfo tuner_interface_info = {
304 (GInterfaceInitFunc) gst_v4l2radio_tuner_interface_reinit,
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);
313 g_type_add_interface_static (type, GST_TYPE_TUNER, &tuner_interface_info);
315 g_type_add_interface_static (type,
316 GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
319 GST_BOILERPLATE_FULL (GstV4l2Radio, gst_v4l2radio, GstElement, GST_TYPE_ELEMENT,
320 gst_v4l2radio_interfaces);
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);
332 gst_v4l2radio_base_init (gpointer gclass)
334 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass);
335 GstV4l2RadioClass *gstv4l2radio_class = GST_V4L2RADIO_CLASS (gclass);
337 GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0,
338 "V4l2 radio element");
340 gstv4l2radio_class->v4l2_class_devices = NULL;
342 gst_element_class_set_details_simple (gstelement_class,
343 "Radio (video4linux2) Tuner",
345 "Controls a Video4Linux2 radio device",
346 "Alexey Chernov <4ernov@gmail.com>");
350 gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
352 GObjectClass *gobject_class;
353 GstElementClass *gstelement_class;
355 gobject_class = (GObjectClass *) klass;
356 gstelement_class = (GstElementClass *) klass;
358 gobject_class->set_property = gst_v4l2radio_set_property;
359 gobject_class->get_property = gst_v4l2radio_get_property;
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));
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));
371 gobject_class->dispose = gst_v4l2radio_dispose;
372 gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize;
374 gstelement_class->change_state =
375 GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state);
380 gst_v4l2radio_init (GstV4l2Radio * filter, GstV4l2RadioClass * gclass)
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);
386 filter->v4l2object->frequency = DEFAULT_FREQUENCY;
387 g_free (filter->v4l2object->videodev);
388 filter->v4l2object->videodev = g_strdup (DEFAULT_PROP_DEVICE);
392 gst_v4l2radio_dispose (GObject * object)
394 GstV4l2Radio *radio = GST_V4L2RADIO (object);
395 gst_v4l2_close (radio->v4l2object);
396 G_OBJECT_CLASS (parent_class)->dispose (object);
400 gst_v4l2radio_finalize (GstV4l2Radio * radio)
402 gst_v4l2_object_destroy (radio->v4l2object);
403 G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (radio));
407 gst_v4l2radio_open (GstV4l2Radio * radio)
409 GstV4l2Object *v4l2object;
411 v4l2object = radio->v4l2object;
412 if (gst_v4l2_open (v4l2object))
413 return gst_v4l2radio_fill_channel_list (radio);
419 gst_v4l2radio_set_defaults (GstV4l2Radio * radio)
421 GstV4l2Object *v4l2object;
422 GstTunerChannel *channel = NULL;
425 v4l2object = radio->v4l2object;
427 if (!GST_IS_TUNER (v4l2object->element))
430 tuner = GST_TUNER (v4l2object->element);
432 if (v4l2object->channel)
433 channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
435 gst_tuner_set_channel (tuner, channel);
438 GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
439 (v4l2object->element)));
441 g_free (v4l2object->channel);
442 v4l2object->channel = g_strdup (channel->label);
443 gst_tuner_channel_changed (tuner, 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);
452 v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
453 if (v4l2object->frequency == 0) {
455 gst_tuner_set_frequency (tuner, channel, MIN_FREQUENCY);
463 gst_v4l2radio_start (GstV4l2Radio * radio)
465 if (!gst_v4l2radio_open (radio))
468 gst_v4l2radio_set_defaults (radio);
474 gst_v4l2radio_stop (GstV4l2Radio * radio)
476 if (!gst_v4l2_object_stop (radio->v4l2object))
482 static GstStateChangeReturn
483 gst_v4l2radio_change_state (GstElement * element, GstStateChange transition)
486 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
488 radio = GST_V4L2RADIO (element);
489 switch (transition) {
490 case GST_STATE_CHANGE_NULL_TO_READY:
492 if (!gst_v4l2radio_start (radio))
493 ret = GST_STATE_CHANGE_FAILURE;
495 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
497 if (!gst_v4l2radio_set_unmute (radio))
498 ret = GST_STATE_CHANGE_FAILURE;
500 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
502 if (!gst_v4l2radio_set_mute (radio))
503 ret = GST_STATE_CHANGE_FAILURE;
505 case GST_STATE_CHANGE_READY_TO_NULL:
507 if (!gst_v4l2radio_stop (radio))
508 ret = GST_STATE_CHANGE_FAILURE;
518 gst_v4l2radio_set_property (GObject * object, guint prop_id,
519 const GValue * value, GParamSpec * pspec)
521 GstV4l2Radio *radio = GST_V4L2RADIO (object);
525 g_free (radio->v4l2object->videodev);
526 radio->v4l2object->videodev =
527 g_strdup ((gchar *) g_value_get_string (value));
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);
538 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
544 gst_v4l2radio_get_property (GObject * object, guint prop_id,
545 GValue * value, GParamSpec * pspec)
547 GstV4l2Radio *radio = GST_V4L2RADIO (object);
551 g_value_set_string (value, radio->v4l2object->videodev);
554 if (gst_v4l2_get_frequency (radio->v4l2object,
555 0, &(radio->v4l2object->frequency)))
556 g_value_set_int (value, radio->v4l2object->frequency);
559 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
564 /* GstURIHandler interface */
566 gst_v4l2radio_uri_get_type (void)
572 gst_v4l2radio_uri_get_protocols (void)
574 static gchar *protocols[] = { (char *) "radio", NULL };
579 gst_v4l2radio_uri_get_uri (GstURIHandler * handler)
581 GstV4l2Radio *radio = GST_V4L2RADIO (handler);
583 if (radio->v4l2object->videodev != NULL) {
584 if (gst_v4l2_get_frequency (radio->v4l2object,
585 0, &(radio->v4l2object->frequency))) {
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);
598 gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri)
600 GstV4l2Radio *radio = GST_V4L2RADIO (handler);
606 if (strcmp (uri, "radio://") != 0) {
609 dfreq = g_ascii_strtod (freq, &end);
611 if (errno || strlen (end))
615 g_object_set (radio, "frequency", ifreq, NULL);
627 gst_v4l2radio_uri_handler_init (gpointer g_iface, gpointer iface_data)
629 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
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;