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