Mailing List Archive

ivtv radio / recording app
Hi

I have written the following to allow use of the radio device on a
PVR-350 for simultaneous recording (in this case using oggenc) and
listening (using artscat), because I couldn't figure out how to get
ivtv-radio to do this (tee didn't work for me, so I could only listen
or record and not both).

It is pretty specific to my circumstances (single card so doesn't
check for more, for example), but I am posting it here in case anyone
finds it useful. I contemplated submitting a patch to ivtv-radio, but
it would alter ivtv-radio's operation in a fairly fundamental way and
I'm not keen on breaking that application for the large group who find
it works just fine as is.

Feel free to ignore.

Cheers (and thank you for ivtv).

--
Tony (echo 'spend!,pocket awide' | sed 'y/acdeikospntw!, /l@omcgtjuba.phi/')


CODE FOLLOWS (I can compile with just "gcc file.c")...

/*
* Records from the PVR-350 radio into an OGG file
* for a specified time, and (optionally) to listen
* to the radio at the same time. Uses ideas from ivtv-radio
* by Hans Verkuil, Brian Jackson, Mark Rafn and Adam Forsyth.
*
* Copyright (C) 2007 Tony Booth <jumbophut@gmail.com>
*
* 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.
*
* For a copy of the GNU General Public License, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/ioctl.h>

#include <linux/videodev2.h>
#include <linux/ivtv.h>

#define DEBUG 0

int alarm_running = 0;
pid_t pid;
char *progname;

void stop_recording(int signum)
{
alarm_running = 0;
}

void usage()
{
printf("\n\n");
printf("Usage: %s -f frequency -o outputfile -t duration \n", progname);
printf("Frequency is in MHz, duration is in seconds\n");
printf("Example: %s -f 101.3 -o test.ogg -t 10\n", progname);
printf("This will record frequency 101.3MHz for 10 seconds,\n");
printf("saving the results to test.ogg.\n\n");
printf("If no duration is supplied recording will continue\n");
printf("until manually terminated (by Ctrl-C, for example)\n");
printf("Exotic options: -e Exit when recording ends\n");
printf("-m Mute radio while recording\n");
printf("-n No recording\n");
}

int main(int argc, char **argv)
{
int rv;
int fh;
int fh2;
struct v4l2_tuner tuner;
struct v4l2_frequency freq;
struct v4l2_capability radio_cap;
struct v4l2_capability audio_cap;
int opt;

const char radio_dev[] = "/dev/radio0";
const char audio_dev[] = "/dev/video24";
int rectime;
char *output_file = NULL;
int exit_after_record, mute, record;
FILE *recout, *catout;

if ((progname = (char *) malloc(strlen(argv[0]) + 1)) == NULL) {
perror("malloc");
exit(1);
}

strcpy(progname, argv[0]);

// set some useful defaults
freq.frequency = (__u32)(101.3 * 16000 + .5);
exit_after_record = 0;
rectime = 0;
mute = 0;
record = 1;
alarm_running = 0;

printf("\n");

while ((opt = getopt(argc, argv, "f:t:o:emnh")) != -1) {
switch (opt) {
case 'f':
freq.frequency = (__u32)(atof(optarg) * 16000 + .5);
break;
case 't':
rectime = atoi(optarg);
if (rectime <= 0) {
printf("Bad -t parameter\n");
usage();
exit(1);
}
break;
case 'o':
if ((output_file = (char *) malloc(strlen(optarg) + 1)) == NULL) {
perror("malloc");
exit(1);
}
strcpy(output_file, optarg);
break;
case 'e':
exit_after_record = 1;
break;
case 'm':
mute = 1;
break;
case 'n':
record = 0;
break;
case 'h':
usage();
exit(1);
break;
default:
printf("Unknown option");
usage();
exit(1);
break;
}

}

if (record && output_file == NULL) {
printf("Required argument not provided");
usage();
exit(1);
}

// Do v4l2 setup here
if ((fh = open(radio_dev, O_RDWR)) < 0) {
perror("open");
exit(1);
}

if (ioctl(fh, VIDIOC_QUERYCAP, &radio_cap)) {
perror("ioctl VIDIOC_QUERYCAP");
exit(1);
}

tuner.index = 0;
int i;
for (i = 0; i <= 3; i++) {
tuner.reserved[i] = 0;
}

if (ioctl(fh, VIDIOC_G_TUNER, &tuner)) {
perror("ioctl VIDIOC_G_TUNER");
exit(1);
}

freq.tuner = 0;
freq.type = V4L2_TUNER_RADIO;

if (ioctl(fh, VIDIOC_S_FREQUENCY, &freq)) {
perror("ioctl VIDIOC_S_FREQUENCY");
exit(1);
};

if ((fh2 = open(audio_dev, O_RDONLY)) < 0) {
perror("open");
exit(1);
}

ioctl(fh2, VIDIOC_QUERYCAP, &audio_cap);
close(fh2);

if(record) {

const char rectemplate[] = "oggenc -r -R 48000 -B 16 -C 2 -o ";
char * recstr;

if ((recstr = (char *) malloc( \
strlen(rectemplate) + strlen(output_file) + 3)) == NULL) {
perror("malloc");
exit(1);
}

strcpy(recstr, rectemplate);
strcat(recstr, output_file);
strcat(recstr, " -");
if ((recout = popen(recstr, "w")) == NULL) {
perror("popen");
exit(1);
}
free(recstr);
}

char catstr[] = "artscat -r 48000 -b 16 -c 2 -";
if ((catout = popen(catstr, "w")) == NULL) {
perror("popen");
exit(1);
}

char buf[1024];
FILE * audf;

if ((audf = fopen(audio_dev, "r")) == NULL) {
perror("fopen");
exit(1);
}

if (record && rectime) {
// Set alarm signal handler here
if (signal(SIGALRM, stop_recording) == SIG_ERR) {
perror("signal");
exit(1);
}
// Set alarm here
alarm(rectime);
}

// This needs to be set even if no alarm is set
// It will allow endless recording to happen if
// no duration was specified
if (record) alarm_running = 1;

if (record) {
while(fread((void *)buf, 1024, 1, audf)) {
if (!mute) {
if (fwrite(buf, 1024, 1, catout) != 1)
printf("Warning: Could not write to artscat. Lost data.\n");
}
if (alarm_running) {
if (fwrite(buf, 1024, 1, recout) != 1)
printf("Warning: Could not write to recorder. Lost data.\n");
} else break;
}
}

if (record && !alarm_running){
int rv;
if ((rv = pclose(recout)) != 0) {
printf("Warning: recorder did not exit normally\n");
printf("Return value = %d", rv);
}
}

if (!exit_after_record) while(fread((void *)buf, 1024, 1, audf)) {
if (!mute) {
if (fwrite(buf, 1024, 1, catout) != 1)
printf("Warning: Could not write to artscat. Lost data.\n");
} else break;
//One day I will add a way to turn off mute via a keystroke
//For now, this doesn't exist, so we might as well exit
//at this point;
}

fclose(audf);

if (record && alarm_running) {
if (fclose(recout)) {
perror("fclose");
}
}

if (fclose(catout)) {
perror("fclose");
}

if (close(fh)) {
perror("close");
}

//No point in the following: they will be freed anyway
//on exit
//free(progname);
//if (output_file != NULL) free(output_file);
}

_______________________________________________
ivtv-devel mailing list
ivtv-devel@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-devel