1 /* GStreamer Tuner
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * tuner.c: tuner design virtual class function wrappers
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., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "tuner.h"
27 
28 #include <string.h>
29 
30 /**
31  * SECTION:gsttuner
32  * @short_description: Interface for elements providing tuner operations
33  *
34  * <refsect2>
35  * <para>
36  * The GstTuner interface is provided by elements that have the ability to
37  * tune into multiple input signals, for example TV or radio capture cards.
38  * </para><para>
39  * The interpretation of 'tuning into' an input stream depends on the element
40  * implementing the interface. For v4lsrc, it might imply selection of an
41  * input source and/or frequency to be configured on a TV card. Another
42  * GstTuner implementation might be to allow selection of an active input pad
43  * from multiple input pads.
44  * </para><para>
45  * That said, the GstTuner interface functions are biased toward the
46  * TV capture scenario.
47  * </para><para>
48  * The general parameters provided are for configuration are:
49  * <itemizedlist>
50  * <listitem>Selection of a current #GstTunerChannel. The current channel
51  * represents the input source (e.g. Composite, S-Video etc for TV capture).
52  * </listitem>
53  * <listitem>The #GstTunerNorm for the channel. The norm chooses the
54  * interpretation of the incoming signal for the current channel. For example,
55  * PAL or NTSC, or more specific variants there-of.
56  * </listitem>
57  * <listitem>Channel frequency. If the current channel has the ability to tune
58  * between multiple frequencies (if it has the GST_TUNER_CHANNEL_FREQUENCY flag)
59  * then the frequency can be changed/retrieved via the
60  * gst_tuner_set_frequency() and gst_tuner_get_frequency() methods.
61  * </listitem>
62  * </itemizedlist>
63  * </para>
64  * <para>
65  * Where applicable, the signal strength can be retrieved and/or monitored
66  * via a signal.
67  * </para>
68  * </refsect2>
69  */
70 
71 /* FIXME 0.11: check if we need to add API for sometimes-supportedness
72  * (aka making up for GstImplementsInterface removal) */
73 
74 /* FIXME 0.11: replace signals with messages (+ make API thread-safe) */
75 
76 enum
77 {
78   NORM_CHANGED,
79   CHANNEL_CHANGED,
80   FREQUENCY_CHANGED,
81   SIGNAL_CHANGED,
82   LAST_SIGNAL
83 };
84 
85 static guint gst_tuner_signals[LAST_SIGNAL] = { 0 };
86 
87 G_DEFINE_INTERFACE (GstTuner, gst_tuner, G_TYPE_INVALID);
88 
89 static void
gst_tuner_default_init(GstTunerInterface * iface)90 gst_tuner_default_init (GstTunerInterface * iface)
91 {
92   static gboolean initialized = FALSE;
93 
94   if (!initialized) {
95     /**
96      * GstTuner::norm-changed:
97      * @tuner: The element providing the GstTuner interface
98      * @norm: The new configured norm.
99      *
100      * Reports that the current #GstTunerNorm has changed.
101      */
102     gst_tuner_signals[NORM_CHANGED] =
103         g_signal_new ("norm-changed",
104         GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
105         G_STRUCT_OFFSET (GstTunerInterface, norm_changed),
106         NULL, NULL,
107         g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_TUNER_NORM);
108     /**
109      * GstTuner::channel-changed:
110      * @tuner: The element providing the GstTuner interface
111      * @channel: The new configured channel.
112      *
113      * Reports that the current #GstTunerChannel has changed.
114      */
115     gst_tuner_signals[CHANNEL_CHANGED] =
116         g_signal_new ("channel-changed",
117         GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
118         G_STRUCT_OFFSET (GstTunerInterface, channel_changed),
119         NULL, NULL,
120         g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
121         GST_TYPE_TUNER_CHANNEL);
122     /**
123      * GstTuner::frequency-changed:
124      * @tuner: The element providing the GstTuner interface
125      * @frequency: The new frequency (an unsigned long)
126      *
127      * Reports that the current frequency has changed.
128      */
129     gst_tuner_signals[FREQUENCY_CHANGED] =
130         g_signal_new ("frequency-changed",
131         GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
132         G_STRUCT_OFFSET (GstTunerInterface, frequency_changed),
133         NULL, NULL,
134         g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_TUNER_CHANNEL,
135         G_TYPE_ULONG);
136     /**
137      * GstTuner::signal-changed:
138      * @tuner: The element providing the GstTuner interface
139      * @channel: The current #GstTunerChannel
140      * @signal: The new signal strength (an integer)
141      *
142      * Reports that the signal strength has changed.
143      *
144      * See Also: gst_tuner_signal_strength()
145      */
146     gst_tuner_signals[SIGNAL_CHANGED] =
147         g_signal_new ("signal-changed",
148         GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
149         G_STRUCT_OFFSET (GstTunerInterface, signal_changed),
150         NULL, NULL,
151         g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_TUNER_CHANNEL,
152         G_TYPE_INT);
153 
154     initialized = TRUE;
155   }
156 
157   /* default virtual functions */
158   iface->list_channels = NULL;
159   iface->set_channel = NULL;
160   iface->get_channel = NULL;
161 
162   iface->list_norms = NULL;
163   iface->set_norm = NULL;
164   iface->get_norm = NULL;
165 
166   iface->set_frequency = NULL;
167   iface->get_frequency = NULL;
168   iface->signal_strength = NULL;
169 }
170 
171 /**
172  * gst_tuner_list_channels:
173  * @tuner: the #GstTuner (a #GstElement) to get the channels from.
174  *
175  * Retrieve a #GList of #GstTunerChannels available
176  * (e.g. 'composite', 's-video', ...) from the given tuner object.
177  *
178  * Returns: A list of channels available on this tuner. The list is
179  *          owned by the GstTuner and must not be freed.
180  */
181 const GList *
gst_tuner_list_channels(GstTuner * tuner)182 gst_tuner_list_channels (GstTuner * tuner)
183 {
184   GstTunerInterface *iface;
185 
186   g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
187 
188   iface = GST_TUNER_GET_INTERFACE (tuner);
189   if (iface->list_channels) {
190     return iface->list_channels (tuner);
191   }
192 
193   return NULL;
194 }
195 
196 /**
197  * gst_tuner_set_channel:
198  * @tuner: the #GstTuner (a #GstElement) that owns the channel.
199  * @channel: the channel to tune to.
200  *
201  * Tunes the object to the given channel, which should be one of the
202  * channels returned by gst_tuner_list_channels().
203  */
204 
205 void
gst_tuner_set_channel(GstTuner * tuner,GstTunerChannel * channel)206 gst_tuner_set_channel (GstTuner * tuner, GstTunerChannel * channel)
207 {
208   GstTunerInterface *iface;
209 
210   g_return_if_fail (GST_IS_TUNER (tuner));
211 
212   iface = GST_TUNER_GET_INTERFACE (tuner);
213   if (iface->set_channel) {
214     iface->set_channel (tuner, channel);
215   }
216 }
217 
218 /**
219  * gst_tuner_get_channel:
220  * @tuner: the #GstTuner (a #GstElement) to get the current channel from.
221  *
222  * Retrieve the current channel from the tuner.
223  *
224  * Returns: the current channel of the tuner object.
225  */
226 
227 GstTunerChannel *
gst_tuner_get_channel(GstTuner * tuner)228 gst_tuner_get_channel (GstTuner * tuner)
229 {
230   GstTunerInterface *iface;
231 
232   g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
233 
234   iface = GST_TUNER_GET_INTERFACE (tuner);
235   if (iface->get_channel) {
236     return iface->get_channel (tuner);
237   }
238 
239   return NULL;
240 }
241 
242 /**
243  * gst_tuner_list_norms:
244  * @tuner: the #GstTuner (*a #GstElement) to get the list of norms from.
245  *
246  * Retrieve a GList of available #GstTunerNorm settings for the currently
247  * tuned channel on the given tuner object.
248  *
249  * Returns: A list of norms available on the current channel for this
250  *          tuner object. The list is owned by the GstTuner and must not
251  *          be freed.
252  */
253 
254 const GList *
gst_tuner_list_norms(GstTuner * tuner)255 gst_tuner_list_norms (GstTuner * tuner)
256 {
257   GstTunerInterface *iface;
258 
259   g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
260 
261   iface = GST_TUNER_GET_INTERFACE (tuner);
262   if (iface->list_norms) {
263     return iface->list_norms (tuner);
264   }
265 
266   return NULL;
267 }
268 
269 /**
270  * gst_tuner_set_norm:
271  * @tuner: the #GstTuner (a #GstElement) to set the norm on.
272  * @norm: the norm to use for the current channel.
273  *
274  * Changes the video norm on this tuner to the given norm, which should be
275  * one of the norms returned by gst_tuner_list_norms().
276  */
277 
278 void
gst_tuner_set_norm(GstTuner * tuner,GstTunerNorm * norm)279 gst_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm)
280 {
281   GstTunerInterface *iface;
282 
283   g_return_if_fail (GST_IS_TUNER (tuner));
284 
285   iface = GST_TUNER_GET_INTERFACE (tuner);
286   if (iface->set_norm) {
287     iface->set_norm (tuner, norm);
288   }
289 }
290 
291 /**
292  * gst_tuner_get_norm:
293  * @tuner: the #GstTuner (a #GstElement) to get the current norm from.
294  *
295  * Get the current video norm from the given tuner object for the
296  * currently selected channel.
297  *
298  * Returns: the current norm.
299  */
300 
301 GstTunerNorm *
gst_tuner_get_norm(GstTuner * tuner)302 gst_tuner_get_norm (GstTuner * tuner)
303 {
304   GstTunerInterface *iface;
305 
306   g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
307 
308   iface = GST_TUNER_GET_INTERFACE (tuner);
309   if (iface->get_norm) {
310     return iface->get_norm (tuner);
311   }
312 
313   return NULL;
314 }
315 
316 /**
317  * gst_tuner_set_frequency:
318  * @tuner: The #GstTuner (a #GstElement) that owns the given channel.
319  * @channel: The #GstTunerChannel to set the frequency on.
320  * @frequency: The frequency to tune in to.
321  *
322  * Sets a tuning frequency on the given tuner/channel. Note that this
323  * requires the given channel to be a "tuning" channel, which can be
324  * checked using GST_TUNER_CHANNEL_HAS_FLAG (), with the proper flag
325  * being GST_TUNER_CHANNEL_FREQUENCY.
326  *
327  * The frequency is in Hz, with minimum steps indicated by the
328  * frequency_multiplicator provided in the #GstTunerChannel. The
329  * valid range is provided in the min_frequency and max_frequency properties
330  * of the #GstTunerChannel.
331  */
332 
333 void
gst_tuner_set_frequency(GstTuner * tuner,GstTunerChannel * channel,gulong frequency)334 gst_tuner_set_frequency (GstTuner * tuner,
335     GstTunerChannel * channel, gulong frequency)
336 {
337   GstTunerInterface *iface;
338 
339   g_return_if_fail (GST_IS_TUNER (tuner));
340   g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
341   g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
342           GST_TUNER_CHANNEL_FREQUENCY));
343 
344   iface = GST_TUNER_GET_INTERFACE (tuner);
345   if (iface->set_frequency) {
346     iface->set_frequency (tuner, channel, frequency);
347   }
348 }
349 
350 /**
351  * gst_tuner_get_frequency:
352  * @tuner: The #GstTuner (a #GstElement) that owns the given channel.
353  * @channel: The #GstTunerChannel to retrieve the frequency from.
354  *
355  * Retrieve the current frequency from the given channel. As for
356  * gst_tuner_set_frequency(), the #GstTunerChannel must support frequency
357  * operations, as indicated by the GST_TUNER_CHANNEL_FREQUENCY flag.
358  *
359  * Returns: The current frequency, or 0 on error.
360  */
361 
362 gulong
gst_tuner_get_frequency(GstTuner * tuner,GstTunerChannel * channel)363 gst_tuner_get_frequency (GstTuner * tuner, GstTunerChannel * channel)
364 {
365   GstTunerInterface *iface;
366 
367   g_return_val_if_fail (GST_IS_TUNER (tuner), 0);
368   g_return_val_if_fail (GST_IS_TUNER_CHANNEL (channel), 0);
369   g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
370           GST_TUNER_CHANNEL_FREQUENCY), 0);
371 
372   iface = GST_TUNER_GET_INTERFACE (tuner);
373 
374   if (iface->get_frequency) {
375     return iface->get_frequency (tuner, channel);
376   }
377 
378   return 0;
379 }
380 
381 /**
382  * gst_tuner_signal_strength:
383  * @tuner: the #GstTuner (a #GstElement) that owns the given channel.
384  * @channel: the #GstTunerChannel to get the signal strength from.
385  *
386  * Get the strength of the signal on this channel. Note that this
387  * requires the current channel to be a "tuning" channel, i.e. a
388  * channel on which frequency can be set. This can be checked using
389  * GST_TUNER_CHANNEL_HAS_FLAG (), and the appropriate flag to check
390  * for is GST_TUNER_CHANNEL_FREQUENCY.
391  *
392  * The valid range of the signal strength is indicated in the
393  * min_signal and max_signal properties of the #GstTunerChannel.
394  *
395  * Returns: Signal strength, or 0 on error.
396  */
397 gint
gst_tuner_signal_strength(GstTuner * tuner,GstTunerChannel * channel)398 gst_tuner_signal_strength (GstTuner * tuner, GstTunerChannel * channel)
399 {
400   GstTunerInterface *iface;
401 
402   g_return_val_if_fail (GST_IS_TUNER (tuner), 0);
403   g_return_val_if_fail (GST_IS_TUNER_CHANNEL (channel), 0);
404   g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
405           GST_TUNER_CHANNEL_FREQUENCY), 0);
406 
407   iface = GST_TUNER_GET_INTERFACE (tuner);
408   if (iface->signal_strength) {
409     return iface->signal_strength (tuner, channel);
410   }
411 
412   return 0;
413 }
414 
415 /**
416  * gst_tuner_find_norm_by_name:
417  * @tuner: A #GstTuner instance
418  * @norm: A string containing the name of a #GstTunerNorm
419  *
420  * Look up a #GstTunerNorm by name.
421  *
422  * Returns: A #GstTunerNorm, or NULL if no norm with the provided name
423  * is available.
424  */
425 GstTunerNorm *
gst_tuner_find_norm_by_name(GstTuner * tuner,gchar * norm)426 gst_tuner_find_norm_by_name (GstTuner * tuner, gchar * norm)
427 {
428   GList *walk;
429 
430   g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
431   g_return_val_if_fail (norm != NULL, NULL);
432 
433   walk = (GList *) gst_tuner_list_norms (tuner);
434   while (walk) {
435     if (strcmp (GST_TUNER_NORM (walk->data)->label, norm) == 0)
436       return GST_TUNER_NORM (walk->data);
437     walk = g_list_next (walk);
438   }
439   return NULL;
440 }
441 
442 /**
443  * gst_tuner_find_channel_by_name:
444  * @tuner: A #GstTuner instance
445  * @channel: A string containing the name of a #GstTunerChannel
446  *
447  * Look up a #GstTunerChannel by name.
448  *
449  * Returns: A #GstTunerChannel, or NULL if no channel with the provided name
450  * is available.
451  */
452 GstTunerChannel *
gst_tuner_find_channel_by_name(GstTuner * tuner,gchar * channel)453 gst_tuner_find_channel_by_name (GstTuner * tuner, gchar * channel)
454 {
455   GList *walk;
456 
457   g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
458   g_return_val_if_fail (channel != NULL, NULL);
459 
460   walk = (GList *) gst_tuner_list_channels (tuner);
461   while (walk) {
462     if (strcmp (GST_TUNER_CHANNEL (walk->data)->label, channel) == 0)
463       return GST_TUNER_CHANNEL (walk->data);
464     walk = g_list_next (walk);
465   }
466   return NULL;
467 }
468 
469 /**
470  * gst_tuner_channel_changed:
471  * @tuner: A #GstTuner instance
472  * @channel: A #GstTunerChannel instance
473  *
474  * Called by elements implementing the #GstTuner interface when the
475  * current channel changes. Fires the #GstTuner::channel-changed signal.
476  */
477 void
gst_tuner_channel_changed(GstTuner * tuner,GstTunerChannel * channel)478 gst_tuner_channel_changed (GstTuner * tuner, GstTunerChannel * channel)
479 {
480   g_return_if_fail (GST_IS_TUNER (tuner));
481   g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
482 
483   g_signal_emit (G_OBJECT (tuner),
484       gst_tuner_signals[CHANNEL_CHANGED], 0, channel);
485 }
486 
487 /**
488  * gst_tuner_norm_changed:
489  * @tuner: A #GstTuner instance
490  * @norm: A #GstTunerNorm instance
491  *
492  * Called by elements implementing the #GstTuner interface when the
493  * current norm changes. Fires the #GstTuner::norm-changed signal.
494  *
495  */
496 void
gst_tuner_norm_changed(GstTuner * tuner,GstTunerNorm * norm)497 gst_tuner_norm_changed (GstTuner * tuner, GstTunerNorm * norm)
498 {
499   g_return_if_fail (GST_IS_TUNER (tuner));
500   g_return_if_fail (GST_IS_TUNER_NORM (norm));
501 
502   g_signal_emit (G_OBJECT (tuner), gst_tuner_signals[NORM_CHANGED], 0, norm);
503 }
504 
505 /**
506  * gst_tuner_frequency_changed:
507  * @tuner: A #GstTuner instance
508  * @channel: The current #GstTunerChannel
509  * @frequency: The new frequency setting
510  *
511  * Called by elements implementing the #GstTuner interface when the
512  * configured frequency changes. Fires the #GstTuner::frequency-changed
513  * signal on the tuner, and the #GstTunerChannel::frequency-changed signal
514  * on the channel.
515  */
516 void
gst_tuner_frequency_changed(GstTuner * tuner,GstTunerChannel * channel,gulong frequency)517 gst_tuner_frequency_changed (GstTuner * tuner,
518     GstTunerChannel * channel, gulong frequency)
519 {
520   g_return_if_fail (GST_IS_TUNER (tuner));
521   g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
522 
523   g_signal_emit (G_OBJECT (tuner),
524       gst_tuner_signals[FREQUENCY_CHANGED], 0, channel, frequency);
525 
526   g_signal_emit_by_name (G_OBJECT (channel), "frequency_changed", frequency);
527 }
528 
529 /**
530  * gst_tuner_signal_changed:
531  * @tuner: A #GstTuner instance
532  * @channel: The current #GstTunerChannel
533  * @signal: The new signal strength
534  *
535  * Called by elements implementing the #GstTuner interface when the
536  * incoming signal strength changes. Fires the #GstTuner::signal-changed
537  * signal on the tuner and the #GstTunerChannel::signal-changed signal on
538  * the channel.
539  */
540 void
gst_tuner_signal_changed(GstTuner * tuner,GstTunerChannel * channel,gint signal)541 gst_tuner_signal_changed (GstTuner * tuner,
542     GstTunerChannel * channel, gint signal)
543 {
544   g_return_if_fail (GST_IS_TUNER (tuner));
545   g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
546 
547   g_signal_emit (G_OBJECT (tuner),
548       gst_tuner_signals[SIGNAL_CHANGED], 0, channel, signal);
549 
550   g_signal_emit_by_name (G_OBJECT (channel), "signal_changed", signal);
551 }
552