f4f2cd64080d897f6773680f96dc2e87bb100eb7
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2tuner.c
1 /* GStreamer Tuner interface implementation
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * gstv4l2tuner.c: tuner interface implementation for V4L2
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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gst/gst.h>
27 #include <gst/tuner/tuner.h>
28
29 #include "gstv4l2tuner.h"
30 #include "gstv4l2element.h"
31 #include "v4l2_calls.h"
32
33 static void     gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *klass);
34 static void     gst_v4l2_tuner_channel_init     (GstV4l2TunerChannel *channel);
35
36 static void     gst_v4l2_tuner_norm_class_init  (GstV4l2TunerNormClass *klass);
37 static void     gst_v4l2_tuner_norm_init        (GstV4l2TunerNorm *norm);
38
39 static const GList *
40                 gst_v4l2_tuner_list_channels    (GstTuner        *mixer);
41 static void     gst_v4l2_tuner_set_channel      (GstTuner        *mixer,
42                                                  GstTunerChannel *channel);
43 static GstTunerChannel *
44                 gst_v4l2_tuner_get_channel      (GstTuner        *mixer);
45
46 static const GList *
47                 gst_v4l2_tuner_list_norms       (GstTuner        *mixer);
48 static void     gst_v4l2_tuner_set_norm         (GstTuner        *mixer,
49                                                  GstTunerNorm    *norm);
50 static GstTunerNorm *
51                 gst_v4l2_tuner_get_norm         (GstTuner        *mixer);
52
53 static void     gst_v4l2_tuner_set_frequency    (GstTuner        *mixer,
54                                                  GstTunerChannel *channel,
55                                                  gulong           frequency);
56 static gulong   gst_v4l2_tuner_get_frequency    (GstTuner        *mixer,
57                                                  GstTunerChannel *channel);
58 static gint     gst_v4l2_tuner_signal_strength  (GstTuner        *mixer,
59                                                  GstTunerChannel *channel);
60
61 static GstTunerNormClass *norm_parent_class = NULL;
62 static GstTunerChannelClass *channel_parent_class = NULL;
63
64 GType
65 gst_v4l2_tuner_channel_get_type (void)
66 {
67   static GType gst_v4l2_tuner_channel_type = 0;
68
69   if (!gst_v4l2_tuner_channel_type) {
70     static const GTypeInfo v4l2_tuner_channel_info = {
71       sizeof (GstV4l2TunerChannelClass),
72       NULL,
73       NULL,
74       (GClassInitFunc) gst_v4l2_tuner_channel_class_init,
75       NULL,
76       NULL,
77       sizeof (GstV4l2TunerChannel),
78       0,
79       (GInstanceInitFunc) gst_v4l2_tuner_channel_init,
80       NULL
81     };
82
83     gst_v4l2_tuner_channel_type =
84         g_type_register_static (GST_TYPE_TUNER_CHANNEL,
85                                 "GstV4l2TunerChannel",
86                                 &v4l2_tuner_channel_info, 0);
87   }
88
89   return gst_v4l2_tuner_channel_type;
90 }
91
92 static void
93 gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *klass)
94 {
95   channel_parent_class = g_type_class_ref (GST_TYPE_TUNER_CHANNEL);
96 }
97
98 static void
99 gst_v4l2_tuner_channel_init (GstV4l2TunerChannel *channel)
100 {
101   channel->index = 0;
102   channel->tuner = 0;
103   channel->audio = 0;
104 }
105
106 GType
107 gst_v4l2_tuner_norm_get_type (void)
108 {
109   static GType gst_v4l2_tuner_norm_type = 0;
110
111   if (!gst_v4l2_tuner_norm_type) {
112     static const GTypeInfo v4l2_tuner_norm_info = {
113       sizeof (GstV4l2TunerNormClass),
114       NULL,
115       NULL,
116       (GClassInitFunc) gst_v4l2_tuner_norm_class_init,
117       NULL,
118       NULL,
119       sizeof (GstV4l2TunerNorm),
120       0,
121       (GInstanceInitFunc) gst_v4l2_tuner_norm_init,
122       NULL
123     };
124
125     gst_v4l2_tuner_norm_type =
126         g_type_register_static (GST_TYPE_TUNER_NORM,
127                                 "GstV4l2TunerNorm",
128                                 &v4l2_tuner_norm_info, 0);
129   }
130
131   return gst_v4l2_tuner_norm_type;
132 }
133
134 static void
135 gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass *klass)
136 {
137   norm_parent_class = g_type_class_ref (GST_TYPE_TUNER_NORM);
138 }
139
140 static void
141 gst_v4l2_tuner_norm_init (GstV4l2TunerNorm *norm)
142 {
143   norm->index = 0;
144 }
145
146 void
147 gst_v4l2_tuner_interface_init (GstTunerClass *klass)
148 {
149   /* default virtual functions */
150   klass->list_channels = gst_v4l2_tuner_list_channels;
151   klass->set_channel = gst_v4l2_tuner_set_channel;
152   klass->get_channel = gst_v4l2_tuner_get_channel;
153
154   klass->list_norms = gst_v4l2_tuner_list_norms;
155   klass->set_norm = gst_v4l2_tuner_set_norm;
156   klass->get_norm = gst_v4l2_tuner_get_norm;
157
158   klass->set_frequency = gst_v4l2_tuner_set_frequency;
159   klass->get_frequency = gst_v4l2_tuner_get_frequency;
160   klass->signal_strength = gst_v4l2_tuner_signal_strength;
161 }
162
163 static gboolean
164 gst_v4l2_tuner_is_sink (GstV4l2Element *v4l2element)
165 {
166   const GList *pads = gst_element_get_pad_list (GST_ELEMENT (v4l2element));
167   GstPadDirection dir = GST_PAD_UNKNOWN;
168
169   /* get direction */
170   if (pads && g_list_length ((GList *) pads) == 1)
171     dir = GST_PAD_DIRECTION (GST_PAD (pads->data));
172
173   return (dir == GST_PAD_SINK);
174 }
175
176 static gboolean
177 gst_v4l2_tuner_contains_channel (GstV4l2Element      *v4l2element,
178                                  GstV4l2TunerChannel *v4l2channel)
179 {
180   const GList *item;
181
182   for (item = v4l2element->channels; item != NULL; item = item->next)
183     if (item->data == v4l2channel)
184       return TRUE;
185
186   return FALSE;
187 }
188
189 static const GList *
190 gst_v4l2_tuner_list_channels (GstTuner *mixer)
191 {
192   /* ... or output, if we're a sink... */
193   return GST_V4L2ELEMENT (mixer)->channels;
194 }
195
196 static void
197 gst_v4l2_tuner_set_channel (GstTuner        *mixer,
198                             GstTunerChannel *channel)
199 {
200   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
201   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
202
203   /* assert that we're opened and that we're using a known item */
204   g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element));
205   g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel));
206
207   /* ... or output, if we're a sink... */
208   if (gst_v4l2_tuner_is_sink (v4l2element) ? 
209       gst_v4l2_set_output (v4l2element, v4l2channel->index) :
210       gst_v4l2_set_input (v4l2element, v4l2channel->index)) {
211     gst_tuner_channel_changed (mixer, channel);
212     g_object_notify (G_OBJECT (v4l2element), "channel");
213   }
214 }
215
216 static GstTunerChannel *
217 gst_v4l2_tuner_get_channel (GstTuner *mixer)
218 {
219   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
220   GList *item;
221   gint channel;
222
223   /* assert that we're opened and that we're using a known item */
224   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL);
225
226   /* ... or output, if we're a sink... */
227   if (gst_v4l2_tuner_is_sink (v4l2element))
228     gst_v4l2_get_output (v4l2element, &channel);
229   else
230     gst_v4l2_get_input (v4l2element, &channel);
231
232   for (item = v4l2element->channels; item != NULL; item = item->next) {
233     if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index)
234       return (GstTunerChannel *) item->data;
235   }
236
237   return NULL;
238 }
239
240 static gboolean
241 gst_v4l2_tuner_contains_norm (GstV4l2Element   *v4l2element,
242                               GstV4l2TunerNorm *v4l2norm)
243 {
244   const GList *item;
245
246   for (item = v4l2element->norms; item != NULL; item = item->next)
247     if (item->data == v4l2norm)
248       return TRUE;
249
250   return FALSE;
251 }
252
253 static const GList *
254 gst_v4l2_tuner_list_norms (GstTuner *mixer)
255 {
256   return GST_V4L2ELEMENT (mixer)->norms;
257 }
258
259 static void
260 gst_v4l2_tuner_set_norm (GstTuner     *mixer,
261                          GstTunerNorm *norm)
262 {
263   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
264   GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm);
265
266   /* assert that we're opened and that we're using a known item */
267   g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element));
268   g_return_if_fail (gst_v4l2_tuner_contains_norm (v4l2element, v4l2norm));
269
270   if (gst_v4l2_set_norm (v4l2element, v4l2norm->index)) {
271     gst_tuner_norm_changed (mixer, norm);
272     g_object_notify (G_OBJECT (v4l2element), "norm"); 
273   }
274 }
275
276 static GstTunerNorm *
277 gst_v4l2_tuner_get_norm (GstTuner *mixer)
278 {
279   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
280   GList *item;
281   v4l2_std_id norm;
282
283   /* assert that we're opened and that we're using a known item */
284   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL);
285
286   gst_v4l2_get_norm (v4l2element, &norm);
287
288   for (item = v4l2element->norms; item != NULL; item = item->next) {
289     if (norm == GST_V4L2_TUNER_NORM (item->data)->index)
290       return (GstTunerNorm *) item->data;
291   }
292
293   return NULL;
294 }
295
296 static void
297 gst_v4l2_tuner_set_frequency (GstTuner        *mixer,
298                               GstTunerChannel *channel,
299                               gulong           frequency)
300 {
301   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
302   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
303   gint chan;
304
305   /* assert that we're opened and that we're using a known item */
306   g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element));
307   g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
308                         GST_TUNER_CHANNEL_FREQUENCY));
309   g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel));
310
311   gst_v4l2_get_input (v4l2element, &chan);
312   if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
313       GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
314     if (gst_v4l2_set_frequency (v4l2element, v4l2channel->tuner, frequency)) {
315       gst_tuner_frequency_changed (mixer, channel, frequency);
316       g_object_notify (G_OBJECT (v4l2element), "frequency"); 
317     }
318   }
319 }
320
321 static gulong
322 gst_v4l2_tuner_get_frequency (GstTuner        *mixer,
323                               GstTunerChannel *channel)
324 {
325   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
326   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
327   gint chan;
328   gulong frequency = 0;
329
330   /* assert that we're opened and that we're using a known item */
331   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0);
332   g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
333                                 GST_TUNER_CHANNEL_FREQUENCY), 0);
334   g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element,
335                                                          v4l2channel), 0);
336
337   gst_v4l2_get_input (v4l2element, &chan);
338   if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
339       GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
340     gst_v4l2_get_frequency (v4l2element, v4l2channel->tuner, &frequency);
341   }
342
343   return frequency;
344 }
345
346 static gint
347 gst_v4l2_tuner_signal_strength (GstTuner        *mixer,
348                                 GstTunerChannel *channel)
349 {
350   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
351   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
352   gint chan;
353   gulong signal = 0;
354
355   /* assert that we're opened and that we're using a known item */
356   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0);
357   g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
358                                 GST_TUNER_CHANNEL_FREQUENCY), 0);
359   g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element,
360                                                          v4l2channel), 0);
361
362   gst_v4l2_get_input (v4l2element, &chan);
363   if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
364       GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
365     gst_v4l2_signal_strength (v4l2element, v4l2channel->tuner, &signal);
366   }
367
368   return signal;
369 }