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; }