snd_pcm_generic_t gen;
char *fname;
int fd;
+ char *ifname;
+ int ifd;
int format;
snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t file_ptr_bytes;
size_t wbuf_size_bytes;
size_t wbuf_used_bytes;
char *wbuf;
+ size_t rbuf_size_bytes;
+ size_t rbuf_used_bytes;
+ char *rbuf;
snd_pcm_channel_area_t *wbuf_areas;
size_t buffer_bytes;
} snd_pcm_file_t;
free((void *)file->fname);
close(file->fd);
}
+ if (file->ifname) {
+ free((void *)file->ifname);
+ close(file->ifd);
+ }
return snd_pcm_generic_close(pcm);
}
{
snd_pcm_file_t *file = pcm->private_data;
snd_pcm_channel_area_t areas[pcm->channels];
- snd_pcm_sframes_t n = snd_pcm_readi(file->gen.slave, buffer, size);
- if (n > 0) {
- snd_pcm_areas_from_buf(pcm, areas, buffer);
- snd_pcm_file_add_frames(pcm, areas, 0, n);
+ snd_pcm_sframes_t n /* , bytesn */;
+
+ if (file->ifd >= 0) {
+ n = /* bytesn = */ read(file->ifd, buffer, size * pcm->frame_bits / 8);
+ if (n > 0)
+ n = n * 8 / pcm->frame_bits;
+ /* SNDERR("DEBUG: channels = %d, sample_bits = %d, frame_bits = %d, bytes = %d, frames = %d",
+ pcm->channels, pcm->sample_bits, pcm->frame_bits, bytesn, n); */
+ } else {
+ n = snd_pcm_readi(file->gen.slave, buffer, size);
+ if (n > 0) {
+ snd_pcm_areas_from_buf(pcm, areas, buffer);
+ snd_pcm_file_add_frames(pcm, areas, 0, n);
+ }
}
return n;
}
{
snd_pcm_file_t *file = pcm->private_data;
snd_pcm_channel_area_t areas[pcm->channels];
- snd_pcm_sframes_t n = snd_pcm_readn(file->gen.slave, bufs, size);
+ snd_pcm_sframes_t n;
+
+ if (file->ifd >= 0) {
+ SNDERR("DEBUG: Noninterleaved read not yet implemented.\n");
+ return 0; /* TODO: Noninterleaved read */
+ }
+
+ n = snd_pcm_readn(file->gen.slave, bufs, size);
if (n > 0) {
snd_pcm_areas_from_bufs(pcm, areas, bufs);
snd_pcm_file_add_frames(pcm, areas, 0, n);
* \brief Creates a new File PCM
* \param pcmp Returns created PCM handle
* \param name Name of PCM
- * \param fname Filename (or NULL if file descriptor is available)
- * \param fd File descriptor
+ * \param fname Output filename (or NULL if file descriptor fd is available)
+ * \param fd Output file descriptor
+ * \param ifname Input filename (or NULL if file descriptor ifd is available)
+ * \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input
+ * redirection will be performed)
* \param fmt File format ("raw" is supported only)
* \param perm File permission
* \param slave Slave PCM handle
* changed in future.
*/
int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
- const char *fname, int fd, const char *fmt, int perm,
- snd_pcm_t *slave, int close_slave)
+ const char *fname, int fd, const char *ifname, int ifd,
+ const char *fmt, int perm, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *pcm;
snd_pcm_file_t *file;
if (fname) {
fd = open(fname, O_WRONLY|O_CREAT, perm);
if (fd < 0) {
- SYSERR("open %s failed", fname);
+ SYSERR("open %s for writing failed", fname);
return -errno;
}
}
close(fd);
return -ENOMEM;
}
-
+
+ if (ifname) {
+ ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */
+ if (ifd < 0) {
+ SYSERR("open %s for reading failed", ifname);
+ if (fname)
+ close(fd);
+ return -errno;
+ }
+ }
+
if (fname)
file->fname = strdup(fname);
+ if (ifname)
+ file->ifname = strdup(ifname);
file->fd = fd;
+ file->ifd = ifd;
file->format = format;
file->gen.slave = slave;
file->gen.close_slave = close_slave;
\section pcm_plugins_file Plugin: File
-This plugin stores contents of a PCM stream to file.
+This plugin stores contents of a PCM stream to file, and optionally
+uses an existing file as an input data source (i.e., "virtual mic")
\code
pcm.name {
# or
pcm { } # Slave PCM definition
}
- file STR # Filename
+ file STR # Output filename
+ or
+ file INT # Output file descriptor number
+ infile STR # Input filename
or
- file INT # File descriptor number
+ infile INT # Input file descriptor number
[format STR] # File format (only "raw" at the moment)
- [perm INT] # File permission (octal, default 0600)
+ [perm INT] # Output file permission (octal, def. 0600)
}
\endcode
int err;
snd_pcm_t *spcm;
snd_config_t *slave = NULL, *sconf;
- const char *fname = NULL;
+ const char *fname = NULL, *ifname = NULL;
const char *format = NULL;
- long fd = -1;
+ long fd = -1, ifd = -1;
int perm = 0600;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
}
continue;
}
+ if (strcmp(id, "infile") == 0) {
+ err = snd_config_get_string(n, &ifname);
+ if (err < 0) {
+ err = snd_config_get_integer(n, &ifd);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+ }
+ continue;
+ }
if (strcmp(id, "perm") == 0) {
char *str;
char *endp;
snd_config_delete(sconf);
if (err < 0)
return err;
- err = snd_pcm_file_open(pcmp, name, fname, fd, format, perm, spcm, 1);
+ err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd, format, perm, spcm, 1);
if (err < 0)
snd_pcm_close(spcm);
return err;