1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_file.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM File Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2000-2001 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - File plugin 10d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 14d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 15d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 16d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 19d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 20d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 24d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 25d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26d5ac70f0Sopenharmony_ci * 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_ci 29d5ac70f0Sopenharmony_ci#include "pcm_local.h" 30d5ac70f0Sopenharmony_ci#include "pcm_plugin.h" 31d5ac70f0Sopenharmony_ci#include "bswap.h" 32d5ac70f0Sopenharmony_ci#include <ctype.h> 33d5ac70f0Sopenharmony_ci#include <string.h> 34d5ac70f0Sopenharmony_ci 35d5ac70f0Sopenharmony_ci#ifndef PIC 36d5ac70f0Sopenharmony_ci/* entry for static linking */ 37d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_file = ""; 38d5ac70f0Sopenharmony_ci#endif 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 41d5ac70f0Sopenharmony_ci 42d5ac70f0Sopenharmony_ci/* keys to be replaced by real values in the filename */ 43d5ac70f0Sopenharmony_ci#define LEADING_KEY '%' /* i.e. %r, %c, %b ... */ 44d5ac70f0Sopenharmony_ci#define RATE_KEY 'r' 45d5ac70f0Sopenharmony_ci#define CHANNELS_KEY 'c' 46d5ac70f0Sopenharmony_ci#define BWIDTH_KEY 'b' 47d5ac70f0Sopenharmony_ci#define FORMAT_KEY 'f' 48d5ac70f0Sopenharmony_ci 49d5ac70f0Sopenharmony_ci/* maximum length of a value */ 50d5ac70f0Sopenharmony_ci#define VALUE_MAXLEN 64 51d5ac70f0Sopenharmony_ci 52d5ac70f0Sopenharmony_citypedef enum _snd_pcm_file_format { 53d5ac70f0Sopenharmony_ci SND_PCM_FILE_FORMAT_RAW, 54d5ac70f0Sopenharmony_ci SND_PCM_FILE_FORMAT_WAV 55d5ac70f0Sopenharmony_ci} snd_pcm_file_format_t; 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_ci/* WAV format chunk */ 58d5ac70f0Sopenharmony_cistruct wav_fmt { 59d5ac70f0Sopenharmony_ci short fmt; 60d5ac70f0Sopenharmony_ci short chan; 61d5ac70f0Sopenharmony_ci int rate; 62d5ac70f0Sopenharmony_ci int bps; 63d5ac70f0Sopenharmony_ci short bwidth; 64d5ac70f0Sopenharmony_ci short bits; 65d5ac70f0Sopenharmony_ci}; 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_citypedef struct { 68d5ac70f0Sopenharmony_ci snd_pcm_generic_t gen; 69d5ac70f0Sopenharmony_ci char *fname; 70d5ac70f0Sopenharmony_ci char *final_fname; 71d5ac70f0Sopenharmony_ci int trunc; 72d5ac70f0Sopenharmony_ci int perm; 73d5ac70f0Sopenharmony_ci int fd; 74d5ac70f0Sopenharmony_ci FILE *pipe; 75d5ac70f0Sopenharmony_ci char *ifname; 76d5ac70f0Sopenharmony_ci int ifd; 77d5ac70f0Sopenharmony_ci int format; 78d5ac70f0Sopenharmony_ci snd_pcm_uframes_t appl_ptr; 79d5ac70f0Sopenharmony_ci snd_pcm_uframes_t file_ptr_bytes; 80d5ac70f0Sopenharmony_ci snd_pcm_uframes_t wbuf_size; 81d5ac70f0Sopenharmony_ci snd_pcm_uframes_t rbuf_size; 82d5ac70f0Sopenharmony_ci size_t wbuf_size_bytes; 83d5ac70f0Sopenharmony_ci size_t wbuf_used_bytes; 84d5ac70f0Sopenharmony_ci char *wbuf; 85d5ac70f0Sopenharmony_ci size_t rbuf_size_bytes; 86d5ac70f0Sopenharmony_ci size_t rbuf_used_bytes; 87d5ac70f0Sopenharmony_ci char *rbuf; 88d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t *wbuf_areas; 89d5ac70f0Sopenharmony_ci size_t buffer_bytes; 90d5ac70f0Sopenharmony_ci struct wav_fmt wav_header; 91d5ac70f0Sopenharmony_ci size_t filelen; 92d5ac70f0Sopenharmony_ci char ifmmap_overwritten; 93d5ac70f0Sopenharmony_ci} snd_pcm_file_t; 94d5ac70f0Sopenharmony_ci 95d5ac70f0Sopenharmony_ci#if __BYTE_ORDER == __LITTLE_ENDIAN 96d5ac70f0Sopenharmony_ci#define TO_LE32(x) (x) 97d5ac70f0Sopenharmony_ci#define TO_LE16(x) (x) 98d5ac70f0Sopenharmony_ci#else 99d5ac70f0Sopenharmony_ci#define TO_LE32(x) bswap_32(x) 100d5ac70f0Sopenharmony_ci#define TO_LE16(x) bswap_16(x) 101d5ac70f0Sopenharmony_ci#endif 102d5ac70f0Sopenharmony_ci 103d5ac70f0Sopenharmony_cistatic ssize_t safe_write(int fd, const void *buf, size_t len) 104d5ac70f0Sopenharmony_ci{ 105d5ac70f0Sopenharmony_ci while (1) { 106d5ac70f0Sopenharmony_ci ssize_t r = write(fd, buf, len); 107d5ac70f0Sopenharmony_ci if (r < 0) { 108d5ac70f0Sopenharmony_ci if (errno == EINTR) 109d5ac70f0Sopenharmony_ci continue; 110d5ac70f0Sopenharmony_ci if (errno == EPIPE) 111d5ac70f0Sopenharmony_ci return -EIO; 112d5ac70f0Sopenharmony_ci return -errno; 113d5ac70f0Sopenharmony_ci } 114d5ac70f0Sopenharmony_ci return r; 115d5ac70f0Sopenharmony_ci } 116d5ac70f0Sopenharmony_ci} 117d5ac70f0Sopenharmony_ci 118d5ac70f0Sopenharmony_cistatic int snd_pcm_file_append_value(char **string_p, char **index_ch_p, 119d5ac70f0Sopenharmony_ci int *len_p, const char *value) 120d5ac70f0Sopenharmony_ci{ 121d5ac70f0Sopenharmony_ci char *string, *index_ch; 122d5ac70f0Sopenharmony_ci int index, len, value_len; 123d5ac70f0Sopenharmony_ci /* input pointer values */ 124d5ac70f0Sopenharmony_ci len = *(len_p); 125d5ac70f0Sopenharmony_ci string = *(string_p); 126d5ac70f0Sopenharmony_ci index_ch = *(index_ch_p); 127d5ac70f0Sopenharmony_ci 128d5ac70f0Sopenharmony_ci value_len = strlen(value); 129d5ac70f0Sopenharmony_ci /* reallocation to accommodate the value */ 130d5ac70f0Sopenharmony_ci index = index_ch - string; 131d5ac70f0Sopenharmony_ci len += value_len; 132d5ac70f0Sopenharmony_ci string = realloc(string, len + 1); 133d5ac70f0Sopenharmony_ci if (!string) 134d5ac70f0Sopenharmony_ci return -ENOMEM; 135d5ac70f0Sopenharmony_ci index_ch = string + index; 136d5ac70f0Sopenharmony_ci /* concatenating the new value */ 137d5ac70f0Sopenharmony_ci strcpy(index_ch, value); 138d5ac70f0Sopenharmony_ci index_ch += value_len; 139d5ac70f0Sopenharmony_ci /* return values */ 140d5ac70f0Sopenharmony_ci *(len_p) = len; 141d5ac70f0Sopenharmony_ci *(string_p) = string; 142d5ac70f0Sopenharmony_ci *(index_ch_p) = index_ch; 143d5ac70f0Sopenharmony_ci return 0; 144d5ac70f0Sopenharmony_ci} 145d5ac70f0Sopenharmony_ci 146d5ac70f0Sopenharmony_cistatic int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p) 147d5ac70f0Sopenharmony_ci{ 148d5ac70f0Sopenharmony_ci char value[VALUE_MAXLEN]; 149d5ac70f0Sopenharmony_ci char *fname = file->fname; 150d5ac70f0Sopenharmony_ci char *new_fname = NULL; 151d5ac70f0Sopenharmony_ci char *old_last_ch, *old_index_ch, *new_index_ch; 152d5ac70f0Sopenharmony_ci int old_len, new_len, err; 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_ci snd_pcm_t *pcm = file->gen.slave; 155d5ac70f0Sopenharmony_ci 156d5ac70f0Sopenharmony_ci /* we want to keep fname, const */ 157d5ac70f0Sopenharmony_ci old_len = new_len = strlen(fname); 158d5ac70f0Sopenharmony_ci old_last_ch = fname + old_len - 1; 159d5ac70f0Sopenharmony_ci new_fname = malloc(new_len + 1); 160d5ac70f0Sopenharmony_ci if (!new_fname) 161d5ac70f0Sopenharmony_ci return -ENOMEM; 162d5ac70f0Sopenharmony_ci 163d5ac70f0Sopenharmony_ci old_index_ch = fname; /* first character of the old name */ 164d5ac70f0Sopenharmony_ci new_index_ch = new_fname; /* first char of the new name */ 165d5ac70f0Sopenharmony_ci 166d5ac70f0Sopenharmony_ci while (old_index_ch <= old_last_ch) { 167d5ac70f0Sopenharmony_ci if (*(old_index_ch) == LEADING_KEY && 168d5ac70f0Sopenharmony_ci old_index_ch != old_last_ch) { 169d5ac70f0Sopenharmony_ci /* is %, not last char, skipping and checking 170d5ac70f0Sopenharmony_ci next char */ 171d5ac70f0Sopenharmony_ci switch (*(++old_index_ch)) { 172d5ac70f0Sopenharmony_ci case RATE_KEY: 173d5ac70f0Sopenharmony_ci snprintf(value, sizeof(value), "%d", 174d5ac70f0Sopenharmony_ci pcm->rate); 175d5ac70f0Sopenharmony_ci err = snd_pcm_file_append_value(&new_fname, 176d5ac70f0Sopenharmony_ci &new_index_ch, &new_len, value); 177d5ac70f0Sopenharmony_ci if (err < 0) 178d5ac70f0Sopenharmony_ci return err; 179d5ac70f0Sopenharmony_ci break; 180d5ac70f0Sopenharmony_ci 181d5ac70f0Sopenharmony_ci case CHANNELS_KEY: 182d5ac70f0Sopenharmony_ci snprintf(value, sizeof(value), "%d", 183d5ac70f0Sopenharmony_ci pcm->channels); 184d5ac70f0Sopenharmony_ci err = snd_pcm_file_append_value(&new_fname, 185d5ac70f0Sopenharmony_ci &new_index_ch, &new_len, value); 186d5ac70f0Sopenharmony_ci if (err < 0) 187d5ac70f0Sopenharmony_ci return err; 188d5ac70f0Sopenharmony_ci break; 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_ci case BWIDTH_KEY: 191d5ac70f0Sopenharmony_ci snprintf(value, sizeof(value), "%d", 192d5ac70f0Sopenharmony_ci pcm->frame_bits/pcm->channels); 193d5ac70f0Sopenharmony_ci err = snd_pcm_file_append_value(&new_fname, 194d5ac70f0Sopenharmony_ci &new_index_ch, &new_len, value); 195d5ac70f0Sopenharmony_ci if (err < 0) 196d5ac70f0Sopenharmony_ci return err; 197d5ac70f0Sopenharmony_ci break; 198d5ac70f0Sopenharmony_ci 199d5ac70f0Sopenharmony_ci case FORMAT_KEY: 200d5ac70f0Sopenharmony_ci err = snd_pcm_file_append_value(&new_fname, 201d5ac70f0Sopenharmony_ci &new_index_ch, &new_len, 202d5ac70f0Sopenharmony_ci snd_pcm_format_name(pcm->format)); 203d5ac70f0Sopenharmony_ci if (err < 0) 204d5ac70f0Sopenharmony_ci return err; 205d5ac70f0Sopenharmony_ci break; 206d5ac70f0Sopenharmony_ci 207d5ac70f0Sopenharmony_ci default: 208d5ac70f0Sopenharmony_ci /* non-key char, just copying */ 209d5ac70f0Sopenharmony_ci *(new_index_ch++) = *(old_index_ch); 210d5ac70f0Sopenharmony_ci } 211d5ac70f0Sopenharmony_ci /* next old char */ 212d5ac70f0Sopenharmony_ci old_index_ch++; 213d5ac70f0Sopenharmony_ci } else { 214d5ac70f0Sopenharmony_ci /* plain copying, shifting both strings to next chars */ 215d5ac70f0Sopenharmony_ci *(new_index_ch++) = *(old_index_ch++); 216d5ac70f0Sopenharmony_ci } 217d5ac70f0Sopenharmony_ci } 218d5ac70f0Sopenharmony_ci /* closing the new string */ 219d5ac70f0Sopenharmony_ci *(new_index_ch) = '\0'; 220d5ac70f0Sopenharmony_ci *(new_fname_p) = new_fname; 221d5ac70f0Sopenharmony_ci return 0; 222d5ac70f0Sopenharmony_ci 223d5ac70f0Sopenharmony_ci} 224d5ac70f0Sopenharmony_ci 225d5ac70f0Sopenharmony_cistatic int snd_pcm_file_open_output_file(snd_pcm_file_t *file) 226d5ac70f0Sopenharmony_ci{ 227d5ac70f0Sopenharmony_ci int err, fd; 228d5ac70f0Sopenharmony_ci 229d5ac70f0Sopenharmony_ci /* fname can contain keys, generating final_fname */ 230d5ac70f0Sopenharmony_ci err = snd_pcm_file_replace_fname(file, &(file->final_fname)); 231d5ac70f0Sopenharmony_ci if (err < 0) 232d5ac70f0Sopenharmony_ci return err; 233d5ac70f0Sopenharmony_ci /*printf("DEBUG - original fname: %s, final fname: %s\n", 234d5ac70f0Sopenharmony_ci file->fname, file->final_fname);*/ 235d5ac70f0Sopenharmony_ci 236d5ac70f0Sopenharmony_ci if (file->final_fname[0] == '|') { 237d5ac70f0Sopenharmony_ci /* pipe mode */ 238d5ac70f0Sopenharmony_ci FILE *pipe; 239d5ac70f0Sopenharmony_ci /* clearing */ 240d5ac70f0Sopenharmony_ci pipe = popen(file->final_fname + 1, "w"); 241d5ac70f0Sopenharmony_ci if (!pipe) { 242d5ac70f0Sopenharmony_ci SYSERR("running %s for writing failed", 243d5ac70f0Sopenharmony_ci file->final_fname); 244d5ac70f0Sopenharmony_ci return -errno; 245d5ac70f0Sopenharmony_ci } 246d5ac70f0Sopenharmony_ci fd = fileno(pipe); 247d5ac70f0Sopenharmony_ci file->pipe = pipe; 248d5ac70f0Sopenharmony_ci } else { 249d5ac70f0Sopenharmony_ci file->pipe = NULL; 250d5ac70f0Sopenharmony_ci if (file->trunc) 251d5ac70f0Sopenharmony_ci fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC, 252d5ac70f0Sopenharmony_ci file->perm); 253d5ac70f0Sopenharmony_ci else { 254d5ac70f0Sopenharmony_ci fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL, 255d5ac70f0Sopenharmony_ci file->perm); 256d5ac70f0Sopenharmony_ci if (fd < 0) { 257d5ac70f0Sopenharmony_ci char *tmpfname = NULL; 258d5ac70f0Sopenharmony_ci int idx, len; 259d5ac70f0Sopenharmony_ci len = strlen(file->final_fname) + 6; 260d5ac70f0Sopenharmony_ci tmpfname = malloc(len); 261d5ac70f0Sopenharmony_ci if (!tmpfname) 262d5ac70f0Sopenharmony_ci return -ENOMEM; 263d5ac70f0Sopenharmony_ci for (idx = 1; idx < 10000; idx++) { 264d5ac70f0Sopenharmony_ci snprintf(tmpfname, len, 265d5ac70f0Sopenharmony_ci "%s.%04d", file->final_fname, 266d5ac70f0Sopenharmony_ci idx); 267d5ac70f0Sopenharmony_ci fd = open(tmpfname, 268d5ac70f0Sopenharmony_ci O_WRONLY|O_CREAT|O_EXCL, 269d5ac70f0Sopenharmony_ci file->perm); 270d5ac70f0Sopenharmony_ci if (fd >= 0) { 271d5ac70f0Sopenharmony_ci free(file->final_fname); 272d5ac70f0Sopenharmony_ci file->final_fname = tmpfname; 273d5ac70f0Sopenharmony_ci break; 274d5ac70f0Sopenharmony_ci } 275d5ac70f0Sopenharmony_ci } 276d5ac70f0Sopenharmony_ci if (fd < 0) { 277d5ac70f0Sopenharmony_ci SYSERR("open %s for writing failed", 278d5ac70f0Sopenharmony_ci file->final_fname); 279d5ac70f0Sopenharmony_ci free(tmpfname); 280d5ac70f0Sopenharmony_ci return -errno; 281d5ac70f0Sopenharmony_ci } 282d5ac70f0Sopenharmony_ci } 283d5ac70f0Sopenharmony_ci } 284d5ac70f0Sopenharmony_ci } 285d5ac70f0Sopenharmony_ci file->fd = fd; 286d5ac70f0Sopenharmony_ci return 0; 287d5ac70f0Sopenharmony_ci} 288d5ac70f0Sopenharmony_ci 289d5ac70f0Sopenharmony_ci/* fill areas with data from input file, return bytes red */ 290d5ac70f0Sopenharmony_cistatic int snd_pcm_file_areas_read_infile(snd_pcm_t *pcm, 291d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 292d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 293d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames) 294d5ac70f0Sopenharmony_ci{ 295d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 296d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas_if[pcm->channels]; 297d5ac70f0Sopenharmony_ci ssize_t bytes; 298d5ac70f0Sopenharmony_ci 299d5ac70f0Sopenharmony_ci if (file->ifd < 0) 300d5ac70f0Sopenharmony_ci return -EBADF; 301d5ac70f0Sopenharmony_ci 302d5ac70f0Sopenharmony_ci if (file->rbuf == NULL) 303d5ac70f0Sopenharmony_ci return -ENOMEM; 304d5ac70f0Sopenharmony_ci 305d5ac70f0Sopenharmony_ci if (file->rbuf_size < frames) { 306d5ac70f0Sopenharmony_ci SYSERR("requested more frames than pcm buffer"); 307d5ac70f0Sopenharmony_ci return -ENOMEM; 308d5ac70f0Sopenharmony_ci } 309d5ac70f0Sopenharmony_ci 310d5ac70f0Sopenharmony_ci bytes = snd_pcm_frames_to_bytes(pcm, frames); 311d5ac70f0Sopenharmony_ci if (bytes < 0) 312d5ac70f0Sopenharmony_ci return bytes; 313d5ac70f0Sopenharmony_ci bytes = read(file->ifd, file->rbuf, bytes); 314d5ac70f0Sopenharmony_ci if (bytes < 0) { 315d5ac70f0Sopenharmony_ci SYSERR("read from file failed, error: %d", bytes); 316d5ac70f0Sopenharmony_ci return bytes; 317d5ac70f0Sopenharmony_ci } 318d5ac70f0Sopenharmony_ci 319d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas_if, file->rbuf); 320d5ac70f0Sopenharmony_ci snd_pcm_areas_copy(areas, offset, areas_if, 0, pcm->channels, snd_pcm_bytes_to_frames(pcm, bytes), pcm->format); 321d5ac70f0Sopenharmony_ci 322d5ac70f0Sopenharmony_ci return bytes; 323d5ac70f0Sopenharmony_ci} 324d5ac70f0Sopenharmony_ci 325d5ac70f0Sopenharmony_cistatic void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt) 326d5ac70f0Sopenharmony_ci{ 327d5ac70f0Sopenharmony_ci fmt->fmt = TO_LE16(0x01); 328d5ac70f0Sopenharmony_ci fmt->chan = TO_LE16(pcm->channels); 329d5ac70f0Sopenharmony_ci fmt->rate = TO_LE32(pcm->rate); 330d5ac70f0Sopenharmony_ci fmt->bwidth = pcm->frame_bits / 8; 331d5ac70f0Sopenharmony_ci fmt->bps = fmt->bwidth * pcm->rate; 332d5ac70f0Sopenharmony_ci fmt->bits = snd_pcm_format_width(pcm->format); 333d5ac70f0Sopenharmony_ci fmt->bps = TO_LE32(fmt->bps); 334d5ac70f0Sopenharmony_ci fmt->bwidth = TO_LE16(fmt->bwidth); 335d5ac70f0Sopenharmony_ci fmt->bits = TO_LE16(fmt->bits); 336d5ac70f0Sopenharmony_ci} 337d5ac70f0Sopenharmony_ci 338d5ac70f0Sopenharmony_cistatic int write_wav_header(snd_pcm_t *pcm) 339d5ac70f0Sopenharmony_ci{ 340d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 341d5ac70f0Sopenharmony_ci ssize_t res; 342d5ac70f0Sopenharmony_ci 343d5ac70f0Sopenharmony_ci static const char header[] = { 344d5ac70f0Sopenharmony_ci 'R', 'I', 'F', 'F', 345d5ac70f0Sopenharmony_ci 0x24, 0, 0, 0, 346d5ac70f0Sopenharmony_ci 'W', 'A', 'V', 'E', 347d5ac70f0Sopenharmony_ci 'f', 'm', 't', ' ', 348d5ac70f0Sopenharmony_ci 0x10, 0, 0, 0, 349d5ac70f0Sopenharmony_ci }; 350d5ac70f0Sopenharmony_ci static const char header2[] = { 351d5ac70f0Sopenharmony_ci 'd', 'a', 't', 'a', 352d5ac70f0Sopenharmony_ci 0, 0, 0, 0 353d5ac70f0Sopenharmony_ci }; 354d5ac70f0Sopenharmony_ci 355d5ac70f0Sopenharmony_ci setup_wav_header(pcm, &file->wav_header); 356d5ac70f0Sopenharmony_ci 357d5ac70f0Sopenharmony_ci res = safe_write(file->fd, header, sizeof(header)); 358d5ac70f0Sopenharmony_ci if (res != sizeof(header)) 359d5ac70f0Sopenharmony_ci goto write_error; 360d5ac70f0Sopenharmony_ci 361d5ac70f0Sopenharmony_ci res = safe_write(file->fd, &file->wav_header, sizeof(file->wav_header)); 362d5ac70f0Sopenharmony_ci if (res != sizeof(file->wav_header)) 363d5ac70f0Sopenharmony_ci goto write_error; 364d5ac70f0Sopenharmony_ci 365d5ac70f0Sopenharmony_ci res = safe_write(file->fd, header2, sizeof(header2)); 366d5ac70f0Sopenharmony_ci if (res != sizeof(header2)) 367d5ac70f0Sopenharmony_ci goto write_error; 368d5ac70f0Sopenharmony_ci 369d5ac70f0Sopenharmony_ci return 0; 370d5ac70f0Sopenharmony_ci 371d5ac70f0Sopenharmony_ciwrite_error: 372d5ac70f0Sopenharmony_ci /* 373d5ac70f0Sopenharmony_ci * print real errno if available and return EIO, reason for this is 374d5ac70f0Sopenharmony_ci * to block possible EPIPE in case file->fd is a pipe. EPIPE from 375d5ac70f0Sopenharmony_ci * file->fd conflicts with EPIPE from playback stream which should 376d5ac70f0Sopenharmony_ci * be used to signal XRUN on playback device 377d5ac70f0Sopenharmony_ci */ 378d5ac70f0Sopenharmony_ci if (res < 0) 379d5ac70f0Sopenharmony_ci SYSERR("%s write header failed, file data may be corrupt", file->fname); 380d5ac70f0Sopenharmony_ci else 381d5ac70f0Sopenharmony_ci SNDERR("%s write header incomplete, file data may be corrupt", file->fname); 382d5ac70f0Sopenharmony_ci 383d5ac70f0Sopenharmony_ci memset(&file->wav_header, 0, sizeof(struct wav_fmt)); 384d5ac70f0Sopenharmony_ci 385d5ac70f0Sopenharmony_ci return -EIO; 386d5ac70f0Sopenharmony_ci} 387d5ac70f0Sopenharmony_ci 388d5ac70f0Sopenharmony_ci/* fix up the length fields in WAV header */ 389d5ac70f0Sopenharmony_cistatic void fixup_wav_header(snd_pcm_t *pcm) 390d5ac70f0Sopenharmony_ci{ 391d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 392d5ac70f0Sopenharmony_ci int len, ret; 393d5ac70f0Sopenharmony_ci 394d5ac70f0Sopenharmony_ci /* RIFF length */ 395d5ac70f0Sopenharmony_ci if (lseek(file->fd, 4, SEEK_SET) == 4) { 396d5ac70f0Sopenharmony_ci len = (file->filelen + 0x24) > 0x7fffffff ? 397d5ac70f0Sopenharmony_ci 0x7fffffff : (int)(file->filelen + 0x24); 398d5ac70f0Sopenharmony_ci len = TO_LE32(len); 399d5ac70f0Sopenharmony_ci ret = safe_write(file->fd, &len, 4); 400d5ac70f0Sopenharmony_ci if (ret < 0) 401d5ac70f0Sopenharmony_ci return; 402d5ac70f0Sopenharmony_ci } 403d5ac70f0Sopenharmony_ci /* data length */ 404d5ac70f0Sopenharmony_ci if (lseek(file->fd, 0x28, SEEK_SET) == 0x28) { 405d5ac70f0Sopenharmony_ci len = file->filelen > 0x7fffffff ? 406d5ac70f0Sopenharmony_ci 0x7fffffff : (int)file->filelen; 407d5ac70f0Sopenharmony_ci len = TO_LE32(len); 408d5ac70f0Sopenharmony_ci ret = safe_write(file->fd, &len, 4); 409d5ac70f0Sopenharmony_ci if (ret < 0) 410d5ac70f0Sopenharmony_ci return; 411d5ac70f0Sopenharmony_ci } 412d5ac70f0Sopenharmony_ci} 413d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 414d5ac70f0Sopenharmony_ci 415d5ac70f0Sopenharmony_ci 416d5ac70f0Sopenharmony_ci 417d5ac70f0Sopenharmony_ci/* return error code in case write failed */ 418d5ac70f0Sopenharmony_cistatic int snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes) 419d5ac70f0Sopenharmony_ci{ 420d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 421d5ac70f0Sopenharmony_ci snd_pcm_sframes_t err = 0; 422d5ac70f0Sopenharmony_ci assert(bytes <= file->wbuf_used_bytes); 423d5ac70f0Sopenharmony_ci 424d5ac70f0Sopenharmony_ci if (file->format == SND_PCM_FILE_FORMAT_WAV && 425d5ac70f0Sopenharmony_ci !file->wav_header.fmt) { 426d5ac70f0Sopenharmony_ci err = write_wav_header(pcm); 427d5ac70f0Sopenharmony_ci if (err < 0) { 428d5ac70f0Sopenharmony_ci file->wbuf_used_bytes = 0; 429d5ac70f0Sopenharmony_ci file->file_ptr_bytes = 0; 430d5ac70f0Sopenharmony_ci return err; 431d5ac70f0Sopenharmony_ci } 432d5ac70f0Sopenharmony_ci } 433d5ac70f0Sopenharmony_ci 434d5ac70f0Sopenharmony_ci while (bytes > 0) { 435d5ac70f0Sopenharmony_ci size_t n = bytes; 436d5ac70f0Sopenharmony_ci size_t cont = file->wbuf_size_bytes - file->file_ptr_bytes; 437d5ac70f0Sopenharmony_ci if (n > cont) 438d5ac70f0Sopenharmony_ci n = cont; 439d5ac70f0Sopenharmony_ci err = safe_write(file->fd, file->wbuf + file->file_ptr_bytes, n); 440d5ac70f0Sopenharmony_ci if (err < 0) { 441d5ac70f0Sopenharmony_ci file->wbuf_used_bytes = 0; 442d5ac70f0Sopenharmony_ci file->file_ptr_bytes = 0; 443d5ac70f0Sopenharmony_ci SYSERR("%s write failed, file data may be corrupt", file->fname); 444d5ac70f0Sopenharmony_ci return err; 445d5ac70f0Sopenharmony_ci } 446d5ac70f0Sopenharmony_ci bytes -= err; 447d5ac70f0Sopenharmony_ci file->wbuf_used_bytes -= err; 448d5ac70f0Sopenharmony_ci file->file_ptr_bytes += err; 449d5ac70f0Sopenharmony_ci if (file->file_ptr_bytes == file->wbuf_size_bytes) 450d5ac70f0Sopenharmony_ci file->file_ptr_bytes = 0; 451d5ac70f0Sopenharmony_ci file->filelen += err; 452d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)err != n) 453d5ac70f0Sopenharmony_ci break; 454d5ac70f0Sopenharmony_ci } 455d5ac70f0Sopenharmony_ci return 0; 456d5ac70f0Sopenharmony_ci} 457d5ac70f0Sopenharmony_ci 458d5ac70f0Sopenharmony_cistatic int snd_pcm_file_add_frames(snd_pcm_t *pcm, 459d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 460d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 461d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames) 462d5ac70f0Sopenharmony_ci{ 463d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 464d5ac70f0Sopenharmony_ci while (frames > 0) { 465d5ac70f0Sopenharmony_ci int err = 0; 466d5ac70f0Sopenharmony_ci snd_pcm_uframes_t n = frames; 467d5ac70f0Sopenharmony_ci snd_pcm_uframes_t cont = file->wbuf_size - file->appl_ptr; 468d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail = file->wbuf_size - snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); 469d5ac70f0Sopenharmony_ci if (n > cont) 470d5ac70f0Sopenharmony_ci n = cont; 471d5ac70f0Sopenharmony_ci if (n > avail) 472d5ac70f0Sopenharmony_ci n = avail; 473d5ac70f0Sopenharmony_ci snd_pcm_areas_copy(file->wbuf_areas, file->appl_ptr, 474d5ac70f0Sopenharmony_ci areas, offset, 475d5ac70f0Sopenharmony_ci pcm->channels, n, pcm->format); 476d5ac70f0Sopenharmony_ci frames -= n; 477d5ac70f0Sopenharmony_ci offset += n; 478d5ac70f0Sopenharmony_ci file->appl_ptr += n; 479d5ac70f0Sopenharmony_ci if (file->appl_ptr == file->wbuf_size) 480d5ac70f0Sopenharmony_ci file->appl_ptr = 0; 481d5ac70f0Sopenharmony_ci file->wbuf_used_bytes += snd_pcm_frames_to_bytes(pcm, n); 482d5ac70f0Sopenharmony_ci if (file->wbuf_used_bytes > file->buffer_bytes) { 483d5ac70f0Sopenharmony_ci err = snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes - file->buffer_bytes); 484d5ac70f0Sopenharmony_ci if (err < 0) 485d5ac70f0Sopenharmony_ci return err; 486d5ac70f0Sopenharmony_ci } 487d5ac70f0Sopenharmony_ci assert(file->wbuf_used_bytes < file->wbuf_size_bytes); 488d5ac70f0Sopenharmony_ci } 489d5ac70f0Sopenharmony_ci return 0; 490d5ac70f0Sopenharmony_ci} 491d5ac70f0Sopenharmony_ci 492d5ac70f0Sopenharmony_cistatic int snd_pcm_file_close(snd_pcm_t *pcm) 493d5ac70f0Sopenharmony_ci{ 494d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 495d5ac70f0Sopenharmony_ci if (file->fname) { 496d5ac70f0Sopenharmony_ci if (file->wav_header.fmt) 497d5ac70f0Sopenharmony_ci fixup_wav_header(pcm); 498d5ac70f0Sopenharmony_ci free((void *)file->fname); 499d5ac70f0Sopenharmony_ci if (file->pipe) { 500d5ac70f0Sopenharmony_ci pclose(file->pipe); 501d5ac70f0Sopenharmony_ci } else if (file->fd >= 0) { 502d5ac70f0Sopenharmony_ci close(file->fd); 503d5ac70f0Sopenharmony_ci } 504d5ac70f0Sopenharmony_ci } 505d5ac70f0Sopenharmony_ci if (file->ifname) { 506d5ac70f0Sopenharmony_ci free((void *)file->ifname); 507d5ac70f0Sopenharmony_ci close(file->ifd); 508d5ac70f0Sopenharmony_ci } 509d5ac70f0Sopenharmony_ci return snd_pcm_generic_close(pcm); 510d5ac70f0Sopenharmony_ci} 511d5ac70f0Sopenharmony_ci 512d5ac70f0Sopenharmony_cistatic int snd_pcm_file_reset(snd_pcm_t *pcm) 513d5ac70f0Sopenharmony_ci{ 514d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 515d5ac70f0Sopenharmony_ci int err = snd_pcm_reset(file->gen.slave); 516d5ac70f0Sopenharmony_ci if (err >= 0) { 517d5ac70f0Sopenharmony_ci /* FIXME: Questionable here */ 518d5ac70f0Sopenharmony_ci snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); 519d5ac70f0Sopenharmony_ci assert(file->wbuf_used_bytes == 0); 520d5ac70f0Sopenharmony_ci } 521d5ac70f0Sopenharmony_ci return err; 522d5ac70f0Sopenharmony_ci} 523d5ac70f0Sopenharmony_ci 524d5ac70f0Sopenharmony_cistatic int snd_pcm_file_drop(snd_pcm_t *pcm) 525d5ac70f0Sopenharmony_ci{ 526d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 527d5ac70f0Sopenharmony_ci int err = snd_pcm_drop(file->gen.slave); 528d5ac70f0Sopenharmony_ci if (err >= 0) { 529d5ac70f0Sopenharmony_ci /* FIXME: Questionable here */ 530d5ac70f0Sopenharmony_ci snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); 531d5ac70f0Sopenharmony_ci assert(file->wbuf_used_bytes == 0); 532d5ac70f0Sopenharmony_ci } 533d5ac70f0Sopenharmony_ci return err; 534d5ac70f0Sopenharmony_ci} 535d5ac70f0Sopenharmony_ci 536d5ac70f0Sopenharmony_ci/* locking */ 537d5ac70f0Sopenharmony_cistatic int snd_pcm_file_drain(snd_pcm_t *pcm) 538d5ac70f0Sopenharmony_ci{ 539d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 540d5ac70f0Sopenharmony_ci int err = snd_pcm_drain(file->gen.slave); 541d5ac70f0Sopenharmony_ci if (err >= 0) { 542d5ac70f0Sopenharmony_ci __snd_pcm_lock(pcm); 543d5ac70f0Sopenharmony_ci snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); 544d5ac70f0Sopenharmony_ci assert(file->wbuf_used_bytes == 0); 545d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 546d5ac70f0Sopenharmony_ci } 547d5ac70f0Sopenharmony_ci return err; 548d5ac70f0Sopenharmony_ci} 549d5ac70f0Sopenharmony_ci 550d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_rewindable(snd_pcm_t *pcm) 551d5ac70f0Sopenharmony_ci{ 552d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 553d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res = snd_pcm_rewindable(file->gen.slave); 554d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); 555d5ac70f0Sopenharmony_ci if (res > n) 556d5ac70f0Sopenharmony_ci res = n; 557d5ac70f0Sopenharmony_ci return res; 558d5ac70f0Sopenharmony_ci} 559d5ac70f0Sopenharmony_ci 560d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 561d5ac70f0Sopenharmony_ci{ 562d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 563d5ac70f0Sopenharmony_ci snd_pcm_sframes_t err; 564d5ac70f0Sopenharmony_ci snd_pcm_uframes_t n; 565d5ac70f0Sopenharmony_ci 566d5ac70f0Sopenharmony_ci n = snd_pcm_frames_to_bytes(pcm, frames); 567d5ac70f0Sopenharmony_ci if (n > file->wbuf_used_bytes) 568d5ac70f0Sopenharmony_ci frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); 569d5ac70f0Sopenharmony_ci err = snd_pcm_rewind(file->gen.slave, frames); 570d5ac70f0Sopenharmony_ci if (err > 0) { 571d5ac70f0Sopenharmony_ci file->appl_ptr = (file->appl_ptr - err + file->wbuf_size) % file->wbuf_size; 572d5ac70f0Sopenharmony_ci n = snd_pcm_frames_to_bytes(pcm, err); 573d5ac70f0Sopenharmony_ci file->wbuf_used_bytes -= n; 574d5ac70f0Sopenharmony_ci } 575d5ac70f0Sopenharmony_ci return err; 576d5ac70f0Sopenharmony_ci} 577d5ac70f0Sopenharmony_ci 578d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_forwardable(snd_pcm_t *pcm) 579d5ac70f0Sopenharmony_ci{ 580d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 581d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res = snd_pcm_forwardable(file->gen.slave); 582d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes); 583d5ac70f0Sopenharmony_ci if (res > n) 584d5ac70f0Sopenharmony_ci res = n; 585d5ac70f0Sopenharmony_ci return res; 586d5ac70f0Sopenharmony_ci} 587d5ac70f0Sopenharmony_ci 588d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 589d5ac70f0Sopenharmony_ci{ 590d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 591d5ac70f0Sopenharmony_ci snd_pcm_sframes_t err; 592d5ac70f0Sopenharmony_ci snd_pcm_uframes_t n; 593d5ac70f0Sopenharmony_ci 594d5ac70f0Sopenharmony_ci n = snd_pcm_frames_to_bytes(pcm, frames); 595d5ac70f0Sopenharmony_ci if (file->wbuf_used_bytes + n > file->wbuf_size_bytes) 596d5ac70f0Sopenharmony_ci frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes); 597d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_forward)(file->gen.slave, frames); 598d5ac70f0Sopenharmony_ci if (err > 0) { 599d5ac70f0Sopenharmony_ci file->appl_ptr = (file->appl_ptr + err) % file->wbuf_size; 600d5ac70f0Sopenharmony_ci n = snd_pcm_frames_to_bytes(pcm, err); 601d5ac70f0Sopenharmony_ci file->wbuf_used_bytes += n; 602d5ac70f0Sopenharmony_ci } 603d5ac70f0Sopenharmony_ci return err; 604d5ac70f0Sopenharmony_ci} 605d5ac70f0Sopenharmony_ci 606d5ac70f0Sopenharmony_ci/* locking */ 607d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) 608d5ac70f0Sopenharmony_ci{ 609d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 610d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 611d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n = _snd_pcm_writei(file->gen.slave, buffer, size); 612d5ac70f0Sopenharmony_ci if (n > 0) { 613d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas, (void*) buffer); 614d5ac70f0Sopenharmony_ci __snd_pcm_lock(pcm); 615d5ac70f0Sopenharmony_ci if (snd_pcm_file_add_frames(pcm, areas, 0, n) < 0) { 616d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 617d5ac70f0Sopenharmony_ci return -EIO; 618d5ac70f0Sopenharmony_ci } 619d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 620d5ac70f0Sopenharmony_ci } 621d5ac70f0Sopenharmony_ci return n; 622d5ac70f0Sopenharmony_ci} 623d5ac70f0Sopenharmony_ci 624d5ac70f0Sopenharmony_ci/* locking */ 625d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 626d5ac70f0Sopenharmony_ci{ 627d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 628d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 629d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n = _snd_pcm_writen(file->gen.slave, bufs, size); 630d5ac70f0Sopenharmony_ci if (n > 0) { 631d5ac70f0Sopenharmony_ci snd_pcm_areas_from_bufs(pcm, areas, bufs); 632d5ac70f0Sopenharmony_ci __snd_pcm_lock(pcm); 633d5ac70f0Sopenharmony_ci if (snd_pcm_file_add_frames(pcm, areas, 0, n) < 0) { 634d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 635d5ac70f0Sopenharmony_ci return -EIO; 636d5ac70f0Sopenharmony_ci } 637d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 638d5ac70f0Sopenharmony_ci } 639d5ac70f0Sopenharmony_ci return n; 640d5ac70f0Sopenharmony_ci} 641d5ac70f0Sopenharmony_ci 642d5ac70f0Sopenharmony_ci/* locking */ 643d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) 644d5ac70f0Sopenharmony_ci{ 645d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 646d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 647d5ac70f0Sopenharmony_ci snd_pcm_sframes_t frames; 648d5ac70f0Sopenharmony_ci 649d5ac70f0Sopenharmony_ci frames = _snd_pcm_readi(file->gen.slave, buffer, size); 650d5ac70f0Sopenharmony_ci if (frames <= 0) 651d5ac70f0Sopenharmony_ci return frames; 652d5ac70f0Sopenharmony_ci 653d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas, buffer); 654d5ac70f0Sopenharmony_ci snd_pcm_file_areas_read_infile(pcm, areas, 0, frames); 655d5ac70f0Sopenharmony_ci __snd_pcm_lock(pcm); 656d5ac70f0Sopenharmony_ci if (snd_pcm_file_add_frames(pcm, areas, 0, frames) < 0) { 657d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 658d5ac70f0Sopenharmony_ci return -EIO; 659d5ac70f0Sopenharmony_ci } 660d5ac70f0Sopenharmony_ci 661d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 662d5ac70f0Sopenharmony_ci 663d5ac70f0Sopenharmony_ci return frames; 664d5ac70f0Sopenharmony_ci} 665d5ac70f0Sopenharmony_ci 666d5ac70f0Sopenharmony_ci/* locking */ 667d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 668d5ac70f0Sopenharmony_ci{ 669d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 670d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 671d5ac70f0Sopenharmony_ci snd_pcm_sframes_t frames; 672d5ac70f0Sopenharmony_ci 673d5ac70f0Sopenharmony_ci frames = _snd_pcm_readn(file->gen.slave, bufs, size); 674d5ac70f0Sopenharmony_ci if (frames <= 0) 675d5ac70f0Sopenharmony_ci return frames; 676d5ac70f0Sopenharmony_ci 677d5ac70f0Sopenharmony_ci snd_pcm_areas_from_bufs(pcm, areas, bufs); 678d5ac70f0Sopenharmony_ci snd_pcm_file_areas_read_infile(pcm, areas, 0, frames); 679d5ac70f0Sopenharmony_ci __snd_pcm_lock(pcm); 680d5ac70f0Sopenharmony_ci if (snd_pcm_file_add_frames(pcm, areas, 0, frames) < 0) { 681d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 682d5ac70f0Sopenharmony_ci return -EIO; 683d5ac70f0Sopenharmony_ci } 684d5ac70f0Sopenharmony_ci 685d5ac70f0Sopenharmony_ci __snd_pcm_unlock(pcm); 686d5ac70f0Sopenharmony_ci 687d5ac70f0Sopenharmony_ci return frames; 688d5ac70f0Sopenharmony_ci} 689d5ac70f0Sopenharmony_ci 690d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm, 691d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 692d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 693d5ac70f0Sopenharmony_ci{ 694d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 695d5ac70f0Sopenharmony_ci snd_pcm_uframes_t ofs; 696d5ac70f0Sopenharmony_ci snd_pcm_uframes_t siz = size; 697d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas; 698d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 699d5ac70f0Sopenharmony_ci 700d5ac70f0Sopenharmony_ci file->ifmmap_overwritten = 0; 701d5ac70f0Sopenharmony_ci 702d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); 703d5ac70f0Sopenharmony_ci if (result >= 0) { 704d5ac70f0Sopenharmony_ci assert(ofs == offset && siz == size); 705d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); 706d5ac70f0Sopenharmony_ci if (result > 0) { 707d5ac70f0Sopenharmony_ci if (snd_pcm_file_add_frames(pcm, areas, ofs, result) < 0) 708d5ac70f0Sopenharmony_ci return -EIO; 709d5ac70f0Sopenharmony_ci } 710d5ac70f0Sopenharmony_ci } 711d5ac70f0Sopenharmony_ci return result; 712d5ac70f0Sopenharmony_ci} 713d5ac70f0Sopenharmony_ci 714d5ac70f0Sopenharmony_cistatic int snd_pcm_file_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, 715d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames) 716d5ac70f0Sopenharmony_ci{ 717d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 718d5ac70f0Sopenharmony_ci int result; 719d5ac70f0Sopenharmony_ci 720d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_begin(file->gen.slave, areas, offset, frames); 721d5ac70f0Sopenharmony_ci if (result < 0) 722d5ac70f0Sopenharmony_ci return result; 723d5ac70f0Sopenharmony_ci 724d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_CAPTURE) 725d5ac70f0Sopenharmony_ci return result; 726d5ac70f0Sopenharmony_ci 727d5ac70f0Sopenharmony_ci /* user may run mmap_begin without mmap_commit multiple times in row */ 728d5ac70f0Sopenharmony_ci if (file->ifmmap_overwritten) 729d5ac70f0Sopenharmony_ci return result; 730d5ac70f0Sopenharmony_ci file->ifmmap_overwritten = 1; 731d5ac70f0Sopenharmony_ci 732d5ac70f0Sopenharmony_ci snd_pcm_file_areas_read_infile(pcm, *areas, *offset, *frames); 733d5ac70f0Sopenharmony_ci 734d5ac70f0Sopenharmony_ci return result; 735d5ac70f0Sopenharmony_ci} 736d5ac70f0Sopenharmony_ci 737d5ac70f0Sopenharmony_cistatic int snd_pcm_file_hw_free(snd_pcm_t *pcm) 738d5ac70f0Sopenharmony_ci{ 739d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 740d5ac70f0Sopenharmony_ci free(file->wbuf); 741d5ac70f0Sopenharmony_ci free(file->wbuf_areas); 742d5ac70f0Sopenharmony_ci free(file->final_fname); 743d5ac70f0Sopenharmony_ci free(file->rbuf); 744d5ac70f0Sopenharmony_ci file->wbuf = NULL; 745d5ac70f0Sopenharmony_ci file->wbuf_areas = NULL; 746d5ac70f0Sopenharmony_ci file->final_fname = NULL; 747d5ac70f0Sopenharmony_ci file->rbuf = NULL; 748d5ac70f0Sopenharmony_ci return snd_pcm_hw_free(file->gen.slave); 749d5ac70f0Sopenharmony_ci} 750d5ac70f0Sopenharmony_ci 751d5ac70f0Sopenharmony_cistatic int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 752d5ac70f0Sopenharmony_ci{ 753d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 754d5ac70f0Sopenharmony_ci unsigned int channel; 755d5ac70f0Sopenharmony_ci snd_pcm_t *slave = file->gen.slave; 756d5ac70f0Sopenharmony_ci int err = _snd_pcm_hw_params_internal(slave, params); 757d5ac70f0Sopenharmony_ci if (err < 0) 758d5ac70f0Sopenharmony_ci return err; 759d5ac70f0Sopenharmony_ci file->buffer_bytes = snd_pcm_frames_to_bytes(slave, slave->buffer_size); 760d5ac70f0Sopenharmony_ci file->wbuf_size = slave->buffer_size * 2; 761d5ac70f0Sopenharmony_ci file->wbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->wbuf_size); 762d5ac70f0Sopenharmony_ci file->wbuf_used_bytes = 0; 763d5ac70f0Sopenharmony_ci file->ifmmap_overwritten = 0; 764d5ac70f0Sopenharmony_ci assert(!file->wbuf); 765d5ac70f0Sopenharmony_ci file->wbuf = malloc(file->wbuf_size_bytes); 766d5ac70f0Sopenharmony_ci if (file->wbuf == NULL) { 767d5ac70f0Sopenharmony_ci snd_pcm_file_hw_free(pcm); 768d5ac70f0Sopenharmony_ci return -ENOMEM; 769d5ac70f0Sopenharmony_ci } 770d5ac70f0Sopenharmony_ci file->wbuf_areas = malloc(sizeof(*file->wbuf_areas) * slave->channels); 771d5ac70f0Sopenharmony_ci if (file->wbuf_areas == NULL) { 772d5ac70f0Sopenharmony_ci snd_pcm_file_hw_free(pcm); 773d5ac70f0Sopenharmony_ci return -ENOMEM; 774d5ac70f0Sopenharmony_ci } 775d5ac70f0Sopenharmony_ci assert(!file->rbuf); 776d5ac70f0Sopenharmony_ci file->rbuf_size = slave->buffer_size; 777d5ac70f0Sopenharmony_ci file->rbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->rbuf_size); 778d5ac70f0Sopenharmony_ci file->rbuf_used_bytes = 0; 779d5ac70f0Sopenharmony_ci file->rbuf = malloc(file->rbuf_size_bytes); 780d5ac70f0Sopenharmony_ci if (file->rbuf == NULL) { 781d5ac70f0Sopenharmony_ci snd_pcm_file_hw_free(pcm); 782d5ac70f0Sopenharmony_ci return -ENOMEM; 783d5ac70f0Sopenharmony_ci } 784d5ac70f0Sopenharmony_ci file->appl_ptr = file->file_ptr_bytes = 0; 785d5ac70f0Sopenharmony_ci for (channel = 0; channel < slave->channels; ++channel) { 786d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t *a = &file->wbuf_areas[channel]; 787d5ac70f0Sopenharmony_ci a->addr = file->wbuf; 788d5ac70f0Sopenharmony_ci a->first = slave->sample_bits * channel; 789d5ac70f0Sopenharmony_ci a->step = slave->frame_bits; 790d5ac70f0Sopenharmony_ci } 791d5ac70f0Sopenharmony_ci if (file->fd < 0) { 792d5ac70f0Sopenharmony_ci err = snd_pcm_file_open_output_file(file); 793d5ac70f0Sopenharmony_ci if (err < 0) { 794d5ac70f0Sopenharmony_ci SYSERR("failed opening output file %s", file->fname); 795d5ac70f0Sopenharmony_ci return err; 796d5ac70f0Sopenharmony_ci } 797d5ac70f0Sopenharmony_ci } 798d5ac70f0Sopenharmony_ci 799d5ac70f0Sopenharmony_ci /* pointer may have changed - e.g if plug is used. */ 800d5ac70f0Sopenharmony_ci snd_pcm_unlink_hw_ptr(pcm, file->gen.slave); 801d5ac70f0Sopenharmony_ci snd_pcm_unlink_appl_ptr(pcm, file->gen.slave); 802d5ac70f0Sopenharmony_ci 803d5ac70f0Sopenharmony_ci snd_pcm_link_hw_ptr(pcm, file->gen.slave); 804d5ac70f0Sopenharmony_ci snd_pcm_link_appl_ptr(pcm, file->gen.slave); 805d5ac70f0Sopenharmony_ci 806d5ac70f0Sopenharmony_ci return 0; 807d5ac70f0Sopenharmony_ci} 808d5ac70f0Sopenharmony_ci 809d5ac70f0Sopenharmony_cistatic void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out) 810d5ac70f0Sopenharmony_ci{ 811d5ac70f0Sopenharmony_ci snd_pcm_file_t *file = pcm->private_data; 812d5ac70f0Sopenharmony_ci if (file->fname) 813d5ac70f0Sopenharmony_ci snd_output_printf(out, "File PCM (file=%s)\n", file->fname); 814d5ac70f0Sopenharmony_ci else 815d5ac70f0Sopenharmony_ci snd_output_printf(out, "File PCM (fd=%d)\n", file->fd); 816d5ac70f0Sopenharmony_ci if (file->final_fname) 817d5ac70f0Sopenharmony_ci snd_output_printf(out, "Final file PCM (file=%s)\n", 818d5ac70f0Sopenharmony_ci file->final_fname); 819d5ac70f0Sopenharmony_ci 820d5ac70f0Sopenharmony_ci if (pcm->setup) { 821d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 822d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 823d5ac70f0Sopenharmony_ci } 824d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 825d5ac70f0Sopenharmony_ci snd_pcm_dump(file->gen.slave, out); 826d5ac70f0Sopenharmony_ci} 827d5ac70f0Sopenharmony_ci 828d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_file_ops = { 829d5ac70f0Sopenharmony_ci .close = snd_pcm_file_close, 830d5ac70f0Sopenharmony_ci .info = snd_pcm_generic_info, 831d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_generic_hw_refine, 832d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_file_hw_params, 833d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_file_hw_free, 834d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_generic_sw_params, 835d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_generic_channel_info, 836d5ac70f0Sopenharmony_ci .dump = snd_pcm_file_dump, 837d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_generic_nonblock, 838d5ac70f0Sopenharmony_ci .async = snd_pcm_generic_async, 839d5ac70f0Sopenharmony_ci .mmap = snd_pcm_generic_mmap, 840d5ac70f0Sopenharmony_ci .munmap = snd_pcm_generic_munmap, 841d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_generic_query_chmaps, 842d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_generic_get_chmap, 843d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_generic_set_chmap, 844d5ac70f0Sopenharmony_ci}; 845d5ac70f0Sopenharmony_ci 846d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { 847d5ac70f0Sopenharmony_ci .status = snd_pcm_generic_status, 848d5ac70f0Sopenharmony_ci .state = snd_pcm_generic_state, 849d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_generic_hwsync, 850d5ac70f0Sopenharmony_ci .delay = snd_pcm_generic_delay, 851d5ac70f0Sopenharmony_ci .prepare = snd_pcm_generic_prepare, 852d5ac70f0Sopenharmony_ci .reset = snd_pcm_file_reset, 853d5ac70f0Sopenharmony_ci .start = snd_pcm_generic_start, 854d5ac70f0Sopenharmony_ci .drop = snd_pcm_file_drop, 855d5ac70f0Sopenharmony_ci .drain = snd_pcm_file_drain, 856d5ac70f0Sopenharmony_ci .pause = snd_pcm_generic_pause, 857d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_file_rewindable, 858d5ac70f0Sopenharmony_ci .rewind = snd_pcm_file_rewind, 859d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_file_forwardable, 860d5ac70f0Sopenharmony_ci .forward = snd_pcm_file_forward, 861d5ac70f0Sopenharmony_ci .resume = snd_pcm_generic_resume, 862d5ac70f0Sopenharmony_ci .link = snd_pcm_generic_link, 863d5ac70f0Sopenharmony_ci .link_slaves = snd_pcm_generic_link_slaves, 864d5ac70f0Sopenharmony_ci .unlink = snd_pcm_generic_unlink, 865d5ac70f0Sopenharmony_ci .writei = snd_pcm_file_writei, 866d5ac70f0Sopenharmony_ci .writen = snd_pcm_file_writen, 867d5ac70f0Sopenharmony_ci .readi = snd_pcm_file_readi, 868d5ac70f0Sopenharmony_ci .readn = snd_pcm_file_readn, 869d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_generic_avail_update, 870d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_file_mmap_commit, 871d5ac70f0Sopenharmony_ci .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, 872d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_generic_poll_descriptors, 873d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_generic_poll_revents, 874d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_generic_htimestamp, 875d5ac70f0Sopenharmony_ci .mmap_begin = snd_pcm_file_mmap_begin, 876d5ac70f0Sopenharmony_ci}; 877d5ac70f0Sopenharmony_ci 878d5ac70f0Sopenharmony_ci/** 879d5ac70f0Sopenharmony_ci * \brief Creates a new File PCM 880d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 881d5ac70f0Sopenharmony_ci * \param name Name of PCM 882d5ac70f0Sopenharmony_ci * \param fname Output filename (or NULL if file descriptor fd is available) 883d5ac70f0Sopenharmony_ci * \param fd Output file descriptor 884d5ac70f0Sopenharmony_ci * \param ifname Input filename (or NULL if file descriptor ifd is available) 885d5ac70f0Sopenharmony_ci * \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input 886d5ac70f0Sopenharmony_ci * redirection will be performed) 887d5ac70f0Sopenharmony_ci * \param trunc Truncate the file if it already exists 888d5ac70f0Sopenharmony_ci * \param fmt File format ("raw" or "wav" are available) 889d5ac70f0Sopenharmony_ci * \param perm File permission 890d5ac70f0Sopenharmony_ci * \param slave Slave PCM handle 891d5ac70f0Sopenharmony_ci * \param close_slave When set, the slave PCM handle is closed with copy PCM 892d5ac70f0Sopenharmony_ci * \param stream the direction of PCM stream 893d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 894d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 895d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 896d5ac70f0Sopenharmony_ci * changed in future. 897d5ac70f0Sopenharmony_ci */ 898d5ac70f0Sopenharmony_ciint snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, 899d5ac70f0Sopenharmony_ci const char *fname, int fd, const char *ifname, int ifd, 900d5ac70f0Sopenharmony_ci int trunc, 901d5ac70f0Sopenharmony_ci const char *fmt, int perm, snd_pcm_t *slave, int close_slave, 902d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream) 903d5ac70f0Sopenharmony_ci{ 904d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 905d5ac70f0Sopenharmony_ci snd_pcm_file_t *file; 906d5ac70f0Sopenharmony_ci snd_pcm_file_format_t format; 907d5ac70f0Sopenharmony_ci struct timespec timespec; 908d5ac70f0Sopenharmony_ci int err; 909d5ac70f0Sopenharmony_ci 910d5ac70f0Sopenharmony_ci assert(pcmp); 911d5ac70f0Sopenharmony_ci if (fmt == NULL || 912d5ac70f0Sopenharmony_ci strcmp(fmt, "raw") == 0) 913d5ac70f0Sopenharmony_ci format = SND_PCM_FILE_FORMAT_RAW; 914d5ac70f0Sopenharmony_ci else if (!strcmp(fmt, "wav")) 915d5ac70f0Sopenharmony_ci format = SND_PCM_FILE_FORMAT_WAV; 916d5ac70f0Sopenharmony_ci else { 917d5ac70f0Sopenharmony_ci SNDERR("file format %s is unknown", fmt); 918d5ac70f0Sopenharmony_ci return -EINVAL; 919d5ac70f0Sopenharmony_ci } 920d5ac70f0Sopenharmony_ci file = calloc(1, sizeof(snd_pcm_file_t)); 921d5ac70f0Sopenharmony_ci if (!file) { 922d5ac70f0Sopenharmony_ci return -ENOMEM; 923d5ac70f0Sopenharmony_ci } 924d5ac70f0Sopenharmony_ci 925d5ac70f0Sopenharmony_ci /* opening output fname is delayed until writing, 926d5ac70f0Sopenharmony_ci when PCM params are known */ 927d5ac70f0Sopenharmony_ci if (fname) 928d5ac70f0Sopenharmony_ci file->fname = strdup(fname); 929d5ac70f0Sopenharmony_ci file->trunc = trunc; 930d5ac70f0Sopenharmony_ci file->perm = perm; 931d5ac70f0Sopenharmony_ci 932d5ac70f0Sopenharmony_ci if (ifname && (stream == SND_PCM_STREAM_CAPTURE)) { 933d5ac70f0Sopenharmony_ci ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */ 934d5ac70f0Sopenharmony_ci if (ifd < 0) { 935d5ac70f0Sopenharmony_ci SYSERR("open %s for reading failed", ifname); 936d5ac70f0Sopenharmony_ci free(file->fname); 937d5ac70f0Sopenharmony_ci free(file); 938d5ac70f0Sopenharmony_ci return -errno; 939d5ac70f0Sopenharmony_ci } 940d5ac70f0Sopenharmony_ci file->ifname = strdup(ifname); 941d5ac70f0Sopenharmony_ci } 942d5ac70f0Sopenharmony_ci file->fd = fd; 943d5ac70f0Sopenharmony_ci file->ifd = ifd; 944d5ac70f0Sopenharmony_ci file->format = format; 945d5ac70f0Sopenharmony_ci file->gen.slave = slave; 946d5ac70f0Sopenharmony_ci file->gen.close_slave = close_slave; 947d5ac70f0Sopenharmony_ci 948d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode); 949d5ac70f0Sopenharmony_ci if (err < 0) { 950d5ac70f0Sopenharmony_ci free(file->fname); 951d5ac70f0Sopenharmony_ci free(file->ifname); 952d5ac70f0Sopenharmony_ci free(file); 953d5ac70f0Sopenharmony_ci return err; 954d5ac70f0Sopenharmony_ci } 955d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_file_ops; 956d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_file_fast_ops; 957d5ac70f0Sopenharmony_ci pcm->private_data = file; 958d5ac70f0Sopenharmony_ci pcm->poll_fd = slave->poll_fd; 959d5ac70f0Sopenharmony_ci pcm->poll_events = slave->poll_events; 960d5ac70f0Sopenharmony_ci pcm->mmap_shadow = 1; 961d5ac70f0Sopenharmony_ci pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; 962d5ac70f0Sopenharmony_ci#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 963d5ac70f0Sopenharmony_ci if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) 964d5ac70f0Sopenharmony_ci pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; 965d5ac70f0Sopenharmony_ci#endif 966d5ac70f0Sopenharmony_ci pcm->stream = stream; 967d5ac70f0Sopenharmony_ci snd_pcm_link_hw_ptr(pcm, slave); 968d5ac70f0Sopenharmony_ci snd_pcm_link_appl_ptr(pcm, slave); 969d5ac70f0Sopenharmony_ci *pcmp = pcm; 970d5ac70f0Sopenharmony_ci return 0; 971d5ac70f0Sopenharmony_ci} 972d5ac70f0Sopenharmony_ci 973d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 974d5ac70f0Sopenharmony_ci 975d5ac70f0Sopenharmony_ci\section pcm_plugins_file Plugin: File 976d5ac70f0Sopenharmony_ci 977d5ac70f0Sopenharmony_ciThis plugin stores contents of a PCM stream to file or pipes the stream 978d5ac70f0Sopenharmony_cito a command, and optionally uses an existing file as an input data source 979d5ac70f0Sopenharmony_ci(i.e., "virtual mic") 980d5ac70f0Sopenharmony_ci 981d5ac70f0Sopenharmony_ci\code 982d5ac70f0Sopenharmony_cipcm.name { 983d5ac70f0Sopenharmony_ci type file # File PCM 984d5ac70f0Sopenharmony_ci slave STR # Slave name 985d5ac70f0Sopenharmony_ci # or 986d5ac70f0Sopenharmony_ci slave { # Slave definition 987d5ac70f0Sopenharmony_ci pcm STR # Slave PCM name 988d5ac70f0Sopenharmony_ci # or 989d5ac70f0Sopenharmony_ci pcm { } # Slave PCM definition 990d5ac70f0Sopenharmony_ci } 991d5ac70f0Sopenharmony_ci file STR # Output filename (or shell command the stream 992d5ac70f0Sopenharmony_ci # will be piped to if STR starts with the pipe 993d5ac70f0Sopenharmony_ci # char). 994d5ac70f0Sopenharmony_ci # STR can contain format keys, replaced by 995d5ac70f0Sopenharmony_ci # real values corresponding to the stream: 996d5ac70f0Sopenharmony_ci # %r rate (replaced with: 48000) 997d5ac70f0Sopenharmony_ci # %c channels (replaced with: 2) 998d5ac70f0Sopenharmony_ci # %b bits per sample (replaced with: 16) 999d5ac70f0Sopenharmony_ci # %f sample format string 1000d5ac70f0Sopenharmony_ci # (replaced with: S16_LE) 1001d5ac70f0Sopenharmony_ci # %% replaced with % 1002d5ac70f0Sopenharmony_ci or 1003d5ac70f0Sopenharmony_ci file INT # Output file descriptor number 1004d5ac70f0Sopenharmony_ci infile STR # Input filename - only raw format 1005d5ac70f0Sopenharmony_ci or 1006d5ac70f0Sopenharmony_ci infile INT # Input file descriptor number 1007d5ac70f0Sopenharmony_ci [format STR] # File format ("raw" or "wav") 1008d5ac70f0Sopenharmony_ci [perm INT] # Output file permission (octal, def. 0600) 1009d5ac70f0Sopenharmony_ci} 1010d5ac70f0Sopenharmony_ci\endcode 1011d5ac70f0Sopenharmony_ci 1012d5ac70f0Sopenharmony_ci\subsection pcm_plugins_file_funcref Function reference 1013d5ac70f0Sopenharmony_ci 1014d5ac70f0Sopenharmony_ci<UL> 1015d5ac70f0Sopenharmony_ci <LI>snd_pcm_file_open() 1016d5ac70f0Sopenharmony_ci <LI>_snd_pcm_file_open() 1017d5ac70f0Sopenharmony_ci</UL> 1018d5ac70f0Sopenharmony_ci 1019d5ac70f0Sopenharmony_ci*/ 1020d5ac70f0Sopenharmony_ci 1021d5ac70f0Sopenharmony_ci/** 1022d5ac70f0Sopenharmony_ci * \brief Creates a new File PCM 1023d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1024d5ac70f0Sopenharmony_ci * \param name Name of PCM 1025d5ac70f0Sopenharmony_ci * \param root Root configuration node 1026d5ac70f0Sopenharmony_ci * \param conf Configuration node with File PCM description 1027d5ac70f0Sopenharmony_ci * \param stream Stream type 1028d5ac70f0Sopenharmony_ci * \param mode Stream mode 1029d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1030d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1031d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1032d5ac70f0Sopenharmony_ci * changed in future. 1033d5ac70f0Sopenharmony_ci */ 1034d5ac70f0Sopenharmony_ciint _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, 1035d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 1036d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1037d5ac70f0Sopenharmony_ci{ 1038d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1039d5ac70f0Sopenharmony_ci int err; 1040d5ac70f0Sopenharmony_ci snd_pcm_t *spcm; 1041d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL, *sconf; 1042d5ac70f0Sopenharmony_ci const char *fname = NULL, *ifname = NULL; 1043d5ac70f0Sopenharmony_ci const char *format = NULL; 1044d5ac70f0Sopenharmony_ci long fd = -1, ifd = -1, trunc = 1; 1045d5ac70f0Sopenharmony_ci long perm = 0600; 1046d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 1047d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1048d5ac70f0Sopenharmony_ci const char *id; 1049d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1050d5ac70f0Sopenharmony_ci continue; 1051d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 1052d5ac70f0Sopenharmony_ci continue; 1053d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 1054d5ac70f0Sopenharmony_ci slave = n; 1055d5ac70f0Sopenharmony_ci continue; 1056d5ac70f0Sopenharmony_ci } 1057d5ac70f0Sopenharmony_ci if (strcmp(id, "format") == 0) { 1058d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &format); 1059d5ac70f0Sopenharmony_ci if (err < 0) { 1060d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1061d5ac70f0Sopenharmony_ci return -EINVAL; 1062d5ac70f0Sopenharmony_ci } 1063d5ac70f0Sopenharmony_ci continue; 1064d5ac70f0Sopenharmony_ci } 1065d5ac70f0Sopenharmony_ci if (strcmp(id, "file") == 0) { 1066d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &fname); 1067d5ac70f0Sopenharmony_ci if (err < 0) { 1068d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &fd); 1069d5ac70f0Sopenharmony_ci if (err < 0) { 1070d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1071d5ac70f0Sopenharmony_ci return -EINVAL; 1072d5ac70f0Sopenharmony_ci } 1073d5ac70f0Sopenharmony_ci } 1074d5ac70f0Sopenharmony_ci continue; 1075d5ac70f0Sopenharmony_ci } 1076d5ac70f0Sopenharmony_ci if (strcmp(id, "infile") == 0) { 1077d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &ifname); 1078d5ac70f0Sopenharmony_ci if (err < 0) { 1079d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &ifd); 1080d5ac70f0Sopenharmony_ci if (err < 0) { 1081d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1082d5ac70f0Sopenharmony_ci return -EINVAL; 1083d5ac70f0Sopenharmony_ci } 1084d5ac70f0Sopenharmony_ci } 1085d5ac70f0Sopenharmony_ci continue; 1086d5ac70f0Sopenharmony_ci } 1087d5ac70f0Sopenharmony_ci if (strcmp(id, "perm") == 0) { 1088d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &perm); 1089d5ac70f0Sopenharmony_ci if (err < 0) { 1090d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1091d5ac70f0Sopenharmony_ci return err; 1092d5ac70f0Sopenharmony_ci } 1093d5ac70f0Sopenharmony_ci if ((perm & ~0777) != 0) { 1094d5ac70f0Sopenharmony_ci SNDERR("The field perm must be a valid file permission"); 1095d5ac70f0Sopenharmony_ci return -EINVAL; 1096d5ac70f0Sopenharmony_ci } 1097d5ac70f0Sopenharmony_ci continue; 1098d5ac70f0Sopenharmony_ci } 1099d5ac70f0Sopenharmony_ci if (strcmp(id, "truncate") == 0) { 1100d5ac70f0Sopenharmony_ci err = snd_config_get_bool(n); 1101d5ac70f0Sopenharmony_ci if (err < 0) 1102d5ac70f0Sopenharmony_ci return -EINVAL; 1103d5ac70f0Sopenharmony_ci trunc = err; 1104d5ac70f0Sopenharmony_ci continue; 1105d5ac70f0Sopenharmony_ci } 1106d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 1107d5ac70f0Sopenharmony_ci return -EINVAL; 1108d5ac70f0Sopenharmony_ci } 1109d5ac70f0Sopenharmony_ci if (!format) { 1110d5ac70f0Sopenharmony_ci snd_config_t *n; 1111d5ac70f0Sopenharmony_ci /* read defaults */ 1112d5ac70f0Sopenharmony_ci if (snd_config_search(root, "defaults.pcm.file_format", &n) >= 0) { 1113d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &format); 1114d5ac70f0Sopenharmony_ci if (err < 0) { 1115d5ac70f0Sopenharmony_ci SNDERR("Invalid file format"); 1116d5ac70f0Sopenharmony_ci return -EINVAL; 1117d5ac70f0Sopenharmony_ci } 1118d5ac70f0Sopenharmony_ci } 1119d5ac70f0Sopenharmony_ci } 1120d5ac70f0Sopenharmony_ci if (!slave) { 1121d5ac70f0Sopenharmony_ci SNDERR("slave is not defined"); 1122d5ac70f0Sopenharmony_ci return -EINVAL; 1123d5ac70f0Sopenharmony_ci } 1124d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave, &sconf, 0); 1125d5ac70f0Sopenharmony_ci if (err < 0) 1126d5ac70f0Sopenharmony_ci return err; 1127d5ac70f0Sopenharmony_ci if ((!fname || strlen(fname) == 0) && fd < 0) { 1128d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1129d5ac70f0Sopenharmony_ci SNDERR("file is not defined"); 1130d5ac70f0Sopenharmony_ci return -EINVAL; 1131d5ac70f0Sopenharmony_ci } 1132d5ac70f0Sopenharmony_ci err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 1133d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1134d5ac70f0Sopenharmony_ci if (err < 0) 1135d5ac70f0Sopenharmony_ci return err; 1136d5ac70f0Sopenharmony_ci err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd, 1137d5ac70f0Sopenharmony_ci trunc, format, perm, spcm, 1, stream); 1138d5ac70f0Sopenharmony_ci if (err < 0) 1139d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1140d5ac70f0Sopenharmony_ci return err; 1141d5ac70f0Sopenharmony_ci} 1142d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 1143d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_file_open, SND_PCM_DLSYM_VERSION); 1144d5ac70f0Sopenharmony_ci#endif 1145