Add truncate option to PCM file plugin

Addeed a new option "truncate" to indicate the behavior of creating
the output file.  When it's true (the default), the file is overwritten
and truncated at creation.  When false, the plugin tries to open a
unique file with a number suffix.

The global behavior of "file" and "tee" PCMs is defined via
defaults.pcm.file_truncate option.  You can overwrite it in ~/.asoundrc.
This commit is contained in:
Takashi Iwai 2008-03-12 16:30:26 +01:00
parent fe8bb13400
commit 3d0dae9099
2 changed files with 51 additions and 4 deletions

View file

@ -95,6 +95,8 @@ defaults.pcm.iec958.card defaults.pcm.card
defaults.pcm.iec958.device defaults.pcm.device defaults.pcm.iec958.device defaults.pcm.device
defaults.pcm.modem.card defaults.pcm.card defaults.pcm.modem.card defaults.pcm.card
defaults.pcm.modem.device defaults.pcm.device defaults.pcm.modem.device defaults.pcm.device
# truncate files via file or tee PCM
defaults.pcm.file_truncate true
defaults.rawmidi.card 0 defaults.rawmidi.card 0
defaults.rawmidi.device 0 defaults.rawmidi.device 0
defaults.rawmidi.subdevice -1 defaults.rawmidi.subdevice -1
@ -270,6 +272,10 @@ pcm.tee {
slave.pcm $SLAVE slave.pcm $SLAVE
file $FILE file $FILE
format $FORMAT format $FORMAT
truncate {
@func refer
name defaults.pcm.file_truncate
}
} }
pcm.file { pcm.file {
@ -285,6 +291,10 @@ pcm.file {
slave.pcm null slave.pcm null
file $FILE file $FILE
format $FORMAT format $FORMAT
truncate {
@func refer
name defaults.pcm.file_truncate
}
} }
pcm.null { pcm.null {

View file

@ -396,6 +396,7 @@ static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
* \param ifname Input filename (or NULL if file descriptor ifd is available) * \param ifname Input filename (or NULL if file descriptor ifd is available)
* \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input * \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input
* redirection will be performed) * redirection will be performed)
* \param trunc Truncate the file if it already exists
* \param fmt File format ("raw" is supported only) * \param fmt File format ("raw" is supported only)
* \param perm File permission * \param perm File permission
* \param slave Slave PCM handle * \param slave Slave PCM handle
@ -406,13 +407,15 @@ static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
* changed in future. * changed in future.
*/ */
int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
const char *fname, int fd, const char *ifname, int ifd, const char *fname, int fd, const char *ifname, int ifd,
int trunc,
const char *fmt, int perm, snd_pcm_t *slave, int close_slave) const char *fmt, int perm, snd_pcm_t *slave, int close_slave)
{ {
snd_pcm_t *pcm; snd_pcm_t *pcm;
snd_pcm_file_t *file; snd_pcm_file_t *file;
snd_pcm_file_format_t format; snd_pcm_file_format_t format;
struct timespec timespec; struct timespec timespec;
char *tmpname = NULL;
int err; int err;
assert(pcmp); assert(pcmp);
@ -424,9 +427,30 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
return -EINVAL; return -EINVAL;
} }
if (fname) { if (fname) {
fd = open(fname, O_WRONLY|O_CREAT, perm); if (trunc)
fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm);
else {
fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm);
if (fd < 0) {
int idx, len;
len = strlen(fname) + 6;
tmpname = malloc(len);
if (!tmpname)
return -ENOMEM;
for (idx = 1; idx < 10000; idx++) {
snprintf(tmpname, len,
"%s.%04d", fname, idx);
fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm);
if (fd >= 0) {
fname = tmpname;
break;
}
}
}
}
if (fd < 0) { if (fd < 0) {
SYSERR("open %s for writing failed", fname); SYSERR("open %s for writing failed", fname);
free(tmpname);
return -errno; return -errno;
} }
} }
@ -434,6 +458,7 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
if (!file) { if (!file) {
if (fname) if (fname)
close(fd); close(fd);
free(tmpname);
return -ENOMEM; return -ENOMEM;
} }
@ -443,6 +468,8 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
SYSERR("open %s for reading failed", ifname); SYSERR("open %s for reading failed", ifname);
if (fname) if (fname)
close(fd); close(fd);
free(file);
free(tmpname);
return -errno; return -errno;
} }
} }
@ -461,6 +488,7 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
if (err < 0) { if (err < 0) {
free(file->fname); free(file->fname);
free(file); free(file);
free(tmpname);
return err; return err;
} }
pcm->ops = &snd_pcm_file_ops; pcm->ops = &snd_pcm_file_ops;
@ -478,6 +506,7 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
snd_pcm_link_appl_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm; *pcmp = pcm;
free(tmpname);
return 0; return 0;
} }
@ -541,7 +570,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
snd_config_t *slave = NULL, *sconf; snd_config_t *slave = NULL, *sconf;
const char *fname = NULL, *ifname = NULL; const char *fname = NULL, *ifname = NULL;
const char *format = NULL; const char *format = NULL;
long fd = -1, ifd = -1; long fd = -1, ifd = -1, trunc = 1;
long perm = 0600; long perm = 0600;
snd_config_for_each(i, next, conf) { snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i); snd_config_t *n = snd_config_iterator_entry(i);
@ -596,6 +625,13 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
} }
continue; continue;
} }
if (strcmp(id, "truncate") == 0) {
err = snd_config_get_bool(n);
if (err < 0)
return -EINVAL;
trunc = err;
continue;
}
SNDERR("Unknown field %s", id); SNDERR("Unknown field %s", id);
return -EINVAL; return -EINVAL;
} }
@ -615,7 +651,8 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
snd_config_delete(sconf); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;
err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd, format, perm, spcm, 1); err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd,
trunc, format, perm, spcm, 1);
if (err < 0) if (err < 0)
snd_pcm_close(spcm); snd_pcm_close(spcm);
return err; return err;