Files
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

405 lines
9.7 KiB
C

#ifndef lint
static char sccsid[] = "@(#)record.c 1.1 94/10/31 Copyr 1989 Sun Micro";
#endif
/* Copyright (c) 1989 by Sun Microsystems, Inc. */
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <stropts.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <multimedia/libaudio.h>
#include <multimedia/audio_device.h>
#define Error (void) fprintf
/* Local variables */
char *prog;
char prog_desc[] = "Record an audio file";
char prog_opts[] = "aft:v:d:i:?"; /* getopt() flags */
char *Stdout = "stdout";
/* XXX - the input buffer size should depend on sample_rate */
unsigned char buf[1024 * 64];
#define MAX_GAIN (100) /* maximum gain */
char *Info = NULL; /* pointer to info data */
unsigned Ilen = 0; /* length of info data */
unsigned Volume = ~0; /* record volume */
double Savevol; /* saved record volume */
int Append = FALSE; /* append to output file */
int Force = FALSE; /* ignore rate differences on append */
double Time = -1.; /* recording time */
unsigned Limit = AUDIO_UNKNOWN_SIZE; /* recording limit */
char *Audio_dev = "/dev/audio";
int Audio_fd = -1; /* file descriptor for audio device */
Audio_hdr Dev_hdr; /* audio header for device */
char *Ofile; /* current filename */
Audio_hdr File_hdr; /* audio header for file */
int Cleanup = FALSE; /* SIGINT sets this flag */
unsigned Size = 0; /* Size of output file */
unsigned Oldsize = 0; /* Size of input file, if append */
/* Global variables */
extern int getopt();
extern int optind;
extern char *optarg;
usage()
{
Error(stderr, "%s -- usage:\n\t%s ", prog_desc, prog);
Error(stderr, "\t[-a] [-v #] [-t #] [-i msg] [-d dev] [file]\n");
Error(stderr, "where:\n\t-a\tAppend to output file\n");
Error(stderr, "\t-f\tIgnore sample rate differences on append\n");
Error(stderr, "\t-v #\tSet record volume (0 - %d)\n", MAX_GAIN);
Error(stderr, "\t-t #\tSpecify record time (hh:mm:ss.dd)\n");
Error(stderr, "\t-i msg\tSpecify a file header information string\n");
Error(stderr, "\t-d dev\tSpecify audio device (default: /dev/audio)\n");
Error(stderr, "\tfile\tRecord to named file\n");
Error(stderr, "\t\tIf no file specified, write to stdout\n");
Error(stderr, "\t\tIf no -t specified, recording continues until ^C\n");
exit(1);
}
void
sigint()
{
/* If this is the first ^C, set a flag for the main loop */
if (!Cleanup && (Audio_fd >= 0)) {
/* flush input queues before exiting */
Cleanup = TRUE;
if (audio_pause_record(Audio_fd) == AUDIO_SUCCESS)
return;
Error(stderr, "%s: could not flush input buffer\n", prog);
}
/* If double ^C, really quit */
if ((Volume != ~0) && (Audio_fd >= 0)) {
(void) audio_set_record_gain(Audio_fd, &Savevol);
}
exit(1);
}
/*
* Record from the audio device to a file.
*/
main(argc, argv)
int argc;
char **argv;
{
int i;
int cnt;
int err;
int ofd;
double vol;
struct stat st;
struct sigvec vec;
struct pollfd pfd;
prog = argv[0]; /* save program initiation name */
err = 0;
while ((i = getopt(argc, argv, prog_opts)) != EOF) switch (i) {
case 'v':
if (parse_unsigned(optarg, &Volume, "-v")) {
err++;
} else if (Volume > MAX_GAIN) {
Error(stderr, "%s: invalid value for -v\n", prog);
err++;
}
break;
case 't':
Time = audio_str_to_secs(optarg);
if ((Time == HUGE_VAL) || (Time < 0.)) {
Error(stderr, "%s: invalid value for -t\n", prog);
err++;
}
break;
case 'd':
Audio_dev = optarg;
break;
case 'f':
Force = TRUE;
break;
case 'a':
Append = TRUE;
break;
case 'i':
Info = optarg; /* set information string */
Ilen = strlen(Info);
break;
case '?':
usage();
/*NOTREACHED*/
}
if (Append && (Info != NULL)) {
Error(stderr, "%s: cannot specify -a and -i\n", prog);
err++;
}
if (err > 0)
exit(1);
argc -= optind; /* update arg pointers */
argv += optind;
/* Open the output file */
if (argc <= 0) {
Ofile = Stdout;
} else {
Ofile = *argv++;
argc--;
/* Interpret "-" filename to mean stdout */
if (strcmp(Ofile, "-") == 0)
Ofile = Stdout;
}
if (Ofile == Stdout) {
ofd = fileno(stdout);
Append = FALSE;
if (isatty(ofd)) {
Error(stderr,
"%s: Specify a filename or redirect stdout to a file\n", prog);
exit(1);
}
} else {
ofd = open(Ofile,
(O_RDWR | O_CREAT | (Append ? 0 : O_TRUNC)), 0666);
if (ofd < 0) {
Error(stderr, "%s: cannot open ", prog);
perror(Ofile);
exit(1);
}
if (Append) {
/*
* Check to make sure we're appending to an audio file.
* It must be a regular file (if zero-length, simply
* write it from scratch). Also, its file header
* must match the input device configuration.
*/
if ((fstat(ofd, &st) < 0) || (!S_ISREG(st.st_mode))) {
Error(stderr, "%s: %s is not a regular file\n",
prog, Ofile);
exit(1);
}
if (st.st_size == 0) {
Append = FALSE;
goto openinput;
}
err = audio_read_filehdr(ofd, &File_hdr,
(char *)NULL, 0);
if (err != AUDIO_SUCCESS) {
Error(stderr,
"%s: %s is not a valid audio file\n",
prog, Ofile);
exit(1);
}
/* Get the current size, if possible */
Oldsize = File_hdr.data_size;
if ((Oldsize == AUDIO_UNKNOWN_SIZE) &&
((err = (int)lseek(ofd, 0L, L_INCR)) >= 0))
Oldsize = st.st_size - err;
/* Seek to end to start append */
if ((int)lseek(ofd, st.st_size, L_SET) < 0) {
Error(stderr,
"%s: cannot find end of %s\n", prog, Ofile);
exit(1);
}
}
}
openinput:
/* Validate and open the audio device */
err = stat(Audio_dev, &st);
if (err < 0) {
Error(stderr, "%s: cannot open ", prog);
perror(Audio_dev);
exit(1);
}
if (!S_ISCHR(st.st_mode)) {
Error(stderr, "%s: %s is not an audio device\n", prog,
Audio_dev);
exit(1);
}
Audio_fd = open(Audio_dev, O_RDONLY | O_NDELAY);
if (Audio_fd < 0) {
if (errno == EBUSY) {
Error(stderr, "%s: %s is busy\n", prog, Audio_dev);
} else {
Error(stderr, "%s: error opening ", prog);
perror(Audio_dev);
}
exit(1);
}
if (audio_get_record_config(Audio_fd, &Dev_hdr) != AUDIO_SUCCESS) {
Error(stderr, "%s: %s is not an audio device\n",
prog, Audio_dev);
exit(1);
}
/* If appending to an existing file, check the configuration */
if (Append) {
char msg[AUDIO_MAX_ENCODE_INFO];
switch (audio_cmp_hdr(&Dev_hdr, &File_hdr)) {
case 0: /* configuration matches */
break;
case 1: /* all but sample rate matches */
if (Force) {
Error(stderr,
"%s: WARNING: appending %.3fkHz data to %s (%.3fkHz)\n",
prog, ((double)Dev_hdr.sample_rate / 1000.),
Ofile, ((double)File_hdr.sample_rate / 1000.));
break;
} /* if not -f, fall through */
default: /* encoding mismatch */
(void) audio_enc_to_str(&Dev_hdr, msg);
Error(stderr,
"%s: device encoding [%s]\n", prog, msg);
(void) audio_enc_to_str(&File_hdr, msg);
Error(stderr,
"\tdoes not match file encoding [%s]\n", msg);
exit(1);
}
} else {
if (audio_write_filehdr(ofd, &Dev_hdr, Info, Ilen) !=
AUDIO_SUCCESS) {
Error(stderr, "%s: error writing header for \n", prog);
perror(Ofile);
exit(1);
}
}
/* If -v flag, set the record volume now */
if (Volume != ~0) {
vol = (double) Volume / (double) MAX_GAIN;
(void) audio_get_record_gain(Audio_fd, &Savevol);
err = audio_set_record_gain(Audio_fd, &vol);
if (err != AUDIO_SUCCESS) {
Error(stderr,
"%s: could not set record volume for %s\n",
prog, Audio_dev);
exit(1);
}
}
/* Set the device up for non-blocking reads */
(void) fcntl(Audio_fd, F_SETFL, fcntl(Audio_fd, F_GETFL, 0) | O_NDELAY);
/* Set up SIGINT handler so that final buffers may be flushed */
vec.sv_handler = sigint;
vec.sv_mask = 0;
vec.sv_flags = 0;
(void) sigvec(SIGINT, &vec, (struct sigvec *)NULL);
/*
* At this point, we're (finally) ready to copy the data.
* Init a poll() structure, to use when there's nothing to read.
*/
if (Time > 0)
Limit = audio_secs_to_bytes(&Dev_hdr, Time);
pfd.fd = Audio_fd;
pfd.events = POLLIN;
while ((Limit == AUDIO_UNKNOWN_SIZE) || (Limit != 0)) {
/* Fill the buffer or read to the time limit */
cnt = read(Audio_fd, (char *)buf,
((Limit != AUDIO_UNKNOWN_SIZE) && (Limit < sizeof (buf)) ?
(int)Limit : sizeof (buf)));
if (cnt == 0) /* normally, eof can't happen */
break;
/* If error, probably have to wait for input */
if (cnt < 0) {
if (Cleanup)
break; /* done if ^C seen */
switch (errno) {
case EAGAIN:
case EWOULDBLOCK:
(void) poll(&pfd, 1L, -1);
break;
default:
Error(stderr, "%s: error reading ", prog);
perror(Audio_dev);
exit(1);
}
continue;
}
err = write(ofd, (char *)buf, cnt);
if (err != cnt) {
Error(stderr, "%s: error writing ", prog);
perror(Ofile);
break;
}
Size += cnt;
if (Limit != AUDIO_UNKNOWN_SIZE)
Limit -= cnt;
}
/* Attempt to rewrite the data_size field of the file header */
if (!Append || (Oldsize != AUDIO_UNKNOWN_SIZE)) {
if (Append)
Size += Oldsize;
(void) audio_rewrite_filesize(ofd, Size);
}
(void) close(ofd); /* close input file */
/* Check for error during record */
if (audio_get_record_error(Audio_fd, (unsigned *)&err) != AUDIO_SUCCESS)
Error(stderr, "%s: error reading device status\n", prog);
else if (err)
Error(stderr, "%s: WARNING: Data overflow occurred\n", prog);
/* Reset record volume */
if (Volume != ~0)
(void) audio_set_record_gain(Audio_fd, &Savevol);
(void) close(Audio_fd);
exit(0);
/*NOTREACHED*/
}
/* Parse an unsigned integer */
parse_unsigned(str, dst, flag)
char *str;
unsigned *dst;
char *flag;
{
char x;
if (sscanf(str, "%u%c", dst, &x) != 1) {
Error(stderr, "%s: invalid value for %s\n", prog, flag);
return (1);
}
return (0);
}