[V4L] multiple tuners with v4l/v4l2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



Hi!

I'm starting to write an application that will use two or more radio
tuners. In my case one tuner is RDS capable. The idea is to use this
tuner for consecutive scanning and updating RDS info, signal strength
for every station and maybe looking for further. The other tuner is for
listen in, of course...
This makes it generally possible to switch to another station
depending on RDS Text, on Traffic Announcements, select the strongest
station or just information fetching (RDS Text)...

You see - something that everybody wants - especially on the road. (:


The problem begins when searching for tuners. So assume a radio card
with three independent tuners (e.g. two FM, one AM).

As far as I can see there is only one way for a V4L2 driver to
represent these tuners: with three devices in /dev.
But V4L is different here:
one device: GCAP --> several channels: GCHAN --> several tuners each:
GTUNER
First issue: Is this just for defining 'virtual' tuners, which cant be
             used together!?
Second issue: Why don't the radio driver support VIDIOCGCHAN?? - The
              application has to guess(!) the number of available
              (virtual) tuners!
Last issue: Is there such hardware/driver?


Bye,
	Robert


PS: The attached program can be used for checks: it traverses the
device via VIDIOC[G|S]CAP/-CHAN/-TUNER/-FREQ and outputs info.
/*
 * Copyright 2000  Robert Siemer <Robert.Siemer@xxxxxx>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/videodev.h>

typedef struct {
	unsigned int freq;
	unsigned int signal;
	unsigned int stereo :1;
	unsigned int rds    :1;
} station;


int main (int argc, char *argv[])
{
	int fd, i;
	struct video_capability vcap;
	struct video_unit       vu;
	struct video_channel    vchan;
	struct video_tuner      vt;
	unsigned long           freq;
	struct video_audio      va;

	if (argc==0)
		return 1;

	fd=open(argv[1], O_RDONLY);
	if (fd<0) {
		perror(program_invocation_short_name);
		return 1;
	}

	if (ioctl(fd, VIDIOCGCAP, &vcap)<0) {
		perror(program_invocation_short_name);
		return 1;
	}

	if (vcap.type&VID_TYPE_TUNER && !vcap.type&VID_TYPE_CAPTURE &&
	    !vcap.type&VID_TYPE_OVERLAY)
		printf("Hmmm, does not look like a radio card - but I don't"
		       " care... [:\n");

	if (vcap.audios!=1)
		printf("Aehm, what does it mean: this device has %d"
		       " audio devices...\n", vcap.audios);

	printf("Found %s, which has %d channel(s).\n", vcap.name,
	       vcap.channels);
	
	if (ioctl(fd, VIDIOCGUNIT, &vu)<0)
		printf("Unable to check for related units...\n");
	else
		printf("video:%d vbi:%d radio:%d audio:%d teletext:%d\n",
		       vu.video, vu.vbi, vu.radio, vu.audio, vu.teletext);

	for (vchan.channel=0; vchan.channel<vcap.channels; vchan.channel++) {
		if (ioctl(fd, VIDIOCGCHAN, &vchan)<0) {
			printf("Sorry, this device is unable to answer on"
			       " VIDIOGCHAN for channel %d...\n",
			       vchan.channel);
			continue;
		}
		printf("Channel%d (%s): ", vchan.channel, vchan.name);
		if (vchan.tuners<1 && !(vchan.flags&VIDEO_VC_TUNER)) {
			printf("no tuner --> no radio\n");
			continue;
		}
		if ((vchan.tuners<1 && vchan.flags&VIDEO_VC_TUNER) ||
		    (vchan.tuners>=1 && !(vchan.flags&VIDEO_VC_TUNER)))
			printf("device is unsure about having some (%d)"
			       " tuners on this channel...\n", vchan.tuners);
		if (vchan.type&VIDEO_TYPE_TV || vchan.type&VIDEO_TYPE_CAMERA
		    || !(vchan.flags&VIDEO_VC_AUDIO)) {
			printf("A radio has audio and no tv/camera input. "
			       "This is not true here...\n");
			continue;
		}
		printf("\n");
		break;
	}

	if (vchan.channel==vcap.channels) vchan.channel=0, vchan.tuners=1;
	printf("Setting to channel %d.\n", vchan.channel);
	if (ioctl(fd, VIDIOCSCHAN, &vchan)<0) {
		printf("VIDIOCSCHAN failed. (This is normal...)\n");
		}

	for (vt.tuner=0; vt.tuner<vchan.tuners; vt.tuner++) {
		if (ioctl(fd, VIDIOCGTUNER, &vt)<0) {
			printf("ioctl() problem with tuner %d.\n", vt.tuner);
			continue;
			}
		printf("Tuner%d (%s): ", vt.tuner, vt.name);
		i=(vt.flags&VIDEO_TUNER_LOW)? 16000 : 16;
		printf("low: %.3f, high: %.3f\n",
		       (double)vt.rangelow/i, (double)vt.rangehigh/i);
		if (ioctl(fd, VIDIOCSTUNER, &vt)<0 ||
		    ioctl(fd, VIDIOCGFREQ, &freq)<0) {
			printf("Sorry, this tuner is just fucked up...\n");
			continue;
			}
		printf(" current frequency (%.3f): ", (double)freq/i);
		if (vt.flags&VIDEO_TUNER_STEREO_ON)
			printf("stereo ");
		if (vt.flags&VIDEO_TUNER_RDS_ON)
			printf("RDS ");
		if (vt.mode&VIDEO_MODE_AUTO)
			printf("(auto)");
		printf("\n");
		printf(" signal:%d\n", vt.signal);
	}


	for (va.audio=0; va.audio<vcap.audios; va.audio++) {
		if (ioctl(fd, VIDIOCGAUDIO, &va)<0) {
			printf("ioctl() problem with audio %d.\n", va.audio);
			continue;
		}
		printf("Audio%d (%s): ", va.audio, va.name);
		printf("mode: ");
		if (va.mode&VIDEO_SOUND_MONO)
			printf("mono ");
		if (va.mode&VIDEO_SOUND_STEREO)
			printf("stereo ");
		if (va.mode&VIDEO_SOUND_LANG1)
			printf("lang1 ");
		if (va.mode&VIDEO_SOUND_LANG2)
			printf("lang2");
		printf("\n");
		printf(" flags: ");
		if (va.flags&VIDEO_AUDIO_MUTABLE) {
			if (va.flags&VIDEO_AUDIO_MUTE)
				printf("muted ");
			else
				printf("unmuted ");
		}
		if (va.flags&VIDEO_AUDIO_VOLUME)
			printf("volume:%d ", va.volume);
		if (va.flags&VIDEO_AUDIO_BASS)
			printf("bass:%d ", va.bass);
		if (va.flags&VIDEO_AUDIO_TREBLE)
			printf("treble:%d ", va.treble);
		printf("balance:%d step:%d\n", va.balance-32768, va.step);
	}
	return 0;
}

[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux