/** * \brief Creates a new File PCM * \param pcmp Returns created PCM handle * \param name Name of PCM * \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 trunc Truncate the file if it already exists * \param fmt File format ("raw" or "wav" are available) * \param perm File permission * \param slave Slave PCM handle * \param close_slave When set, the slave PCM handle is closed with copy PCM * \param stream the direction of PCM stream * \retval zero on success otherwise a negative error code * \warning Using of this function might be dangerous in the sense * of compatibility reasons. The prototype might be freely * changed in future. */ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, const char *fname, int fd, const char *ifname, int ifd, int trunc, const char *fmt, int perm, snd_pcm_t *slave, int close_slave, snd_pcm_stream_t stream) { snd_pcm_t *pcm; snd_pcm_file_t *file; snd_pcm_file_format_t format; struct timespec timespec; int err; assert(pcmp); if (fmt == NULL || strcmp(fmt, "raw") == 0) format = SND_PCM_FILE_FORMAT_RAW; else if (!strcmp(fmt, "wav")) format = SND_PCM_FILE_FORMAT_WAV; else { SNDERR("file format %s is unknown", fmt); return -EINVAL; } file = calloc(1, sizeof(snd_pcm_file_t)); if (!file) { return -ENOMEM; } /* opening output fname is delayed until writing, when PCM params are known */ if (fname) file->fname = strdup(fname); file->trunc = trunc; file->perm = perm; if (ifname && (stream == SND_PCM_STREAM_CAPTURE)) { ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */ if (ifd < 0) { SYSERR("open %s for reading failed", ifname); free(file->fname); free(file); return -errno; } file->ifname = strdup(ifname); } file->fd = fd; file->ifd = ifd; file->format = format; file->gen.slave = slave; file->gen.close_slave = close_slave; err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode); if (err < 0) { free(file->fname); free(file->ifname); free(file); return err; } pcm->ops = &snd_pcm_file_ops; pcm->fast_ops = &snd_pcm_file_fast_ops; pcm->private_data = file; pcm->poll_fd = slave->poll_fd; pcm->poll_events = slave->poll_events; pcm->mmap_shadow = 1; pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; #endif pcm->stream = stream; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; return 0; }
/** * \brief Creates a new File PCM * \param pcmp Returns created PCM handle * \param name Name of PCM * \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 trunc Truncate the file if it already exists * \param fmt File format ("raw" or "wav" are available) * \param perm File permission * \param slave Slave PCM handle * \param close_slave When set, the slave PCM handle is closed with copy PCM * \retval zero on success otherwise a negative error code * \warning Using of this function might be dangerous in the sense * of compatibility reasons. The prototype might be freely * changed in future. */ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, const char *fname, int fd, const char *ifname, int ifd, int trunc, const char *fmt, int perm, snd_pcm_t *slave, int close_slave) { snd_pcm_t *pcm; snd_pcm_file_t *file; snd_pcm_file_format_t format; struct timespec timespec; char *tmpname = NULL; int err; assert(pcmp); if (fmt == NULL || strcmp(fmt, "raw") == 0) format = SND_PCM_FILE_FORMAT_RAW; else if (!strcmp(fmt, "wav")) format = SND_PCM_FILE_FORMAT_WAV; else { SNDERR("file format %s is unknown", fmt); return -EINVAL; } if (fname) { 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) { SYSERR("open %s for writing failed", fname); free(tmpname); return -errno; } } file = calloc(1, sizeof(snd_pcm_file_t)); if (!file) { if (fname) close(fd); free(tmpname); 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); free(file); free(tmpname); 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; err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode); if (err < 0) { free(file->fname); free(file); free(tmpname); return err; } pcm->ops = &snd_pcm_file_ops; pcm->fast_ops = &snd_pcm_file_fast_ops; pcm->private_data = file; pcm->poll_fd = slave->poll_fd; pcm->poll_events = slave->poll_events; pcm->mmap_shadow = 1; #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) pcm->monotonic = clock_gettime(CLOCK_MONOTONIC, ×pec) == 0; #else pcm->monotonic = 0; #endif snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; free(tmpname); return 0; }
/** * \brief Creates a new File PCM * \param pcmp Returns created PCM handle * \param name Name of PCM * \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 * \param close_slave When set, the slave PCM handle is closed with copy PCM * \retval zero on success otherwise a negative error code * \warning Using of this function might be dangerous in the sense * of compatibility reasons. The prototype might be freely * changed in future. */ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, 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; snd_pcm_file_format_t format; int err; assert(pcmp); if (fmt == NULL || strcmp(fmt, "raw") == 0) format = SND_PCM_FILE_FORMAT_RAW; else { SNDERR("file format %s is unknown", fmt); return -EINVAL; } if (fname) { fd = open(fname, O_WRONLY|O_CREAT, perm); if (fd < 0) { SYSERR("open %s for writing failed", fname); return -errno; } } file = calloc(1, sizeof(snd_pcm_file_t)); if (!file) { if (fname) 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; err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode); if (err < 0) { free(file->fname); free(file); return err; } pcm->ops = &snd_pcm_file_ops; pcm->fast_ops = &snd_pcm_file_fast_ops; pcm->private_data = file; pcm->poll_fd = slave->poll_fd; pcm->poll_events = slave->poll_events; pcm->mmap_shadow = 1; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; return 0; }