hythmbox-2.98/plugins/fmradio/rb-radio-tuner-v4l2.c

No issues found

  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Copyright (C) 2007  James Henstridge <james@jamesh.id.au>
  4  *
  5  *  This program is free software; you can redistribute it and/or modify
  6  *  it under the terms of the GNU General Public License as published by
  7  *  the Free Software Foundation; either version 2 of the License, or
  8  *  (at your option) any later version.
  9  *
 10  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 11  *  GStreamer plugins to be used and distributed together with GStreamer
 12  *  and Rhythmbox. This permission is above and beyond the permissions granted
 13  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 14  *  you may extend this exception to your version of the code, but you are not
 15  *  obligated to do so. If you do not wish to do so, delete this exception
 16  *  statement from your version.
 17  *
 18  *  This program is distributed in the hope that it will be useful,
 19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21  *  GNU General Public License for more details.
 22  *
 23  *  You should have received a copy of the GNU General Public License
 24  *  along with this program; if not, write to the Free Software
 25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 26  *
 27  */
 28 
 29 #include <config.h>
 30 
 31 #include <sys/types.h>
 32 #include <sys/ioctl.h>
 33 #include <fcntl.h>
 34 #include <unistd.h>
 35 #include <errno.h>
 36 #include <string.h>
 37 
 38 #include <linux/videodev2.h>
 39 
 40 #include <glib.h>
 41 
 42 #include "rb-debug.h"
 43 #include "rb-radio-tuner.h"
 44 
 45 struct _RBRadioTunerPrivate {
 46 	int fd;
 47 	guint32 range_low;
 48 	guint32 range_high;
 49 	guint32 current_frequency;
 50 	guint32 freq_mul;
 51 };
 52 
 53 G_DEFINE_DYNAMIC_TYPE (RBRadioTuner, rb_radio_tuner, G_TYPE_OBJECT);
 54 
 55 static void rb_radio_tuner_finalize (GObject *object);
 56 
 57 static void
 58 rb_radio_tuner_class_init (RBRadioTunerClass *class)
 59 {
 60 	GObjectClass *object_class = G_OBJECT_CLASS (class);
 61 
 62 	object_class->finalize = rb_radio_tuner_finalize;
 63 
 64 	g_type_class_add_private (class, sizeof (RBRadioTunerPrivate));
 65 }
 66 
 67 static void
 68 rb_radio_tuner_class_finalize (RBRadioTunerClass *class)
 69 {
 70 }
 71 
 72 static void
 73 rb_radio_tuner_init (RBRadioTuner *self)
 74 {
 75 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RB_TYPE_RADIO_TUNER,
 76 						 RBRadioTunerPrivate);
 77 	self->priv->fd = -1;
 78 }
 79 
 80 static void
 81 rb_radio_tuner_finalize (GObject *object)
 82 {
 83 	RBRadioTuner *self = (RBRadioTuner *)object;
 84 
 85 	g_free (self->card_name);
 86 	self->card_name = NULL;
 87 	if (self->priv->fd >= 0)
 88 		close (self->priv->fd);
 89 	self->priv->fd = -1;
 90 
 91         G_OBJECT_CLASS (rb_radio_tuner_parent_class)->finalize (object);
 92 }
 93 
 94 RBRadioTuner *
 95 rb_radio_tuner_new (const gchar *devname, GError **err)
 96 {
 97 	int fd = -1;
 98 	struct v4l2_capability caps;
 99 	struct v4l2_tuner tuner;
100 	RBRadioTuner *self;
101 
102 	if (devname == NULL)
103 		devname = "/dev/radio0";
104 
105 	fd = open(devname, O_RDONLY);
106 	if (fd < 0) {
107 		g_warning("Could not open device %s", devname);
108 		goto err;
109 	}
110 	memset (&caps, 0, sizeof (caps));
111 	if (ioctl (fd, VIDIOC_QUERYCAP, &caps) < 0) {
112 		g_warning("Could not query device capabilities: %s",
113 			g_strerror(errno));
114 		goto err;
115 	}
116 	if ((caps.capabilities & V4L2_CAP_TUNER) == 0) {
117 		g_warning("Device is not a tuner");
118 		goto err;
119 	}
120 
121 	/* check the tuner */
122 	memset(&tuner, 0, sizeof(tuner));
123 	tuner.index = 0;
124 	if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) {
125 		g_warning("Could not query tuner info: %s", g_strerror(errno));
126 		goto err;
127 	}
128 	if (tuner.type != V4L2_TUNER_RADIO) {
129 		g_warning("Device is not a radio tuner");
130 		goto err;
131 	}
132 
133 
134 	self = RB_RADIO_TUNER (g_object_new (RB_TYPE_RADIO_TUNER, NULL));
135 
136 	/* fill in information */
137 	self->priv->fd = fd;
138 	self->card_name = g_strndup((const char *)caps.card,
139 				    sizeof(caps.card));
140 	self->priv->range_low = tuner.rangelow;
141 	self->priv->range_high = tuner.rangehigh;
142 	if ((tuner.capability & V4L2_TUNER_CAP_LOW) != 0)
143 		self->priv->freq_mul = 16000;
144 	else
145 		self->priv->freq_mul = 16;
146 
147 	self->min_freq = (double)self->priv->range_low / self->priv->freq_mul;
148 	self->max_freq = (double)self->priv->range_high / self->priv->freq_mul;
149 
150 	rb_radio_tuner_update (self);
151 	return self;
152 
153  err:
154 	if (fd >= 0)
155 		close (fd);
156 	return NULL;
157 }
158 
159 void
160 rb_radio_tuner_update (RBRadioTuner *self)
161 {
162 	struct v4l2_tuner tuner;
163 	struct v4l2_control control;
164 	struct v4l2_frequency frequency;
165 	gboolean has_changed = FALSE;
166 
167 	memset (&tuner, 0, sizeof (tuner));
168 	tuner.index = 0;
169 	if (ioctl (self->priv->fd, VIDIOC_G_TUNER, &tuner) >= 0) {
170 		if (self->is_stereo != (tuner.audmode==V4L2_TUNER_MODE_STEREO))
171 			has_changed = TRUE;
172 		self->is_stereo = (tuner.audmode==V4L2_TUNER_MODE_STEREO);
173 
174 		if (self->signal != tuner.signal)
175 			has_changed = TRUE;
176 		self->signal = tuner.signal;
177 	}
178 
179 	memset (&control, 0, sizeof (control));
180 	control.id = V4L2_CID_AUDIO_MUTE;
181 	if (ioctl (self->priv->fd, VIDIOC_G_CTRL, &control) >= 0) {
182 		control.value = !!control.value;
183 		if (self->is_muted != control.value)
184 			has_changed = TRUE;
185 		self->is_muted = control.value;
186 	}
187 
188 	memset (&frequency, 0, sizeof (frequency));
189 	frequency.tuner = 0;
190 	if (ioctl (self->priv->fd, VIDIOC_G_FREQUENCY, &frequency) >= 0) {
191 		if (self->priv->current_frequency != frequency.frequency)
192 			has_changed = TRUE;
193 		self->priv->current_frequency = frequency.frequency;
194 		self->frequency = (double)frequency.frequency
195 			/ self->priv->freq_mul;
196 	}
197 
198 	rb_debug ("Tuner %s", has_changed ? "has changed" : "has not changed");
199 
200 #if 0
201 	if (has_changed) {
202 		g_signal_emit (self, CHANGED);
203 	}
204 #endif
205 }
206 
207 gboolean
208 rb_radio_tuner_set_frequency (RBRadioTuner *self, double frequency)
209 {
210 	struct v4l2_frequency freq;
211 	guint new_freq;
212 
213 	new_freq = frequency * self->priv->freq_mul;
214 	new_freq = CLAMP (new_freq,
215 			  self->priv->range_low, self->priv->range_high);
216 
217 	memset (&freq, 0, sizeof (freq));
218 	freq.tuner = 0;
219 	freq.type = V4L2_TUNER_RADIO;
220 	freq.frequency = new_freq;
221 	return ioctl (self->priv->fd, VIDIOC_S_FREQUENCY, &freq) >= 0;
222 }
223 
224 gboolean
225 rb_radio_tuner_set_mute (RBRadioTuner *self, gboolean mute)
226 {
227 	struct v4l2_control control;
228 
229 	memset(&control, 0, sizeof(control));
230 	control.id = V4L2_CID_AUDIO_MUTE;
231 	control.value = !!mute;
232 	return ioctl (self->priv->fd, VIDIOC_S_CTRL, &control) >= 0;
233 }
234 
235 void
236 _rb_radio_tuner_register_type (GTypeModule *module)
237 {
238 	rb_radio_tuner_register_type (module);
239 }