1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_copy.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Copy Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2000-2001 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Copy conversion 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 33d5ac70f0Sopenharmony_ci#ifndef PIC 34d5ac70f0Sopenharmony_ci/* entry for static linking */ 35d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_copy = ""; 36d5ac70f0Sopenharmony_ci#endif 37d5ac70f0Sopenharmony_ci 38d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 39d5ac70f0Sopenharmony_citypedef struct { 40d5ac70f0Sopenharmony_ci /* This field need to be the first */ 41d5ac70f0Sopenharmony_ci snd_pcm_plugin_t plug; 42d5ac70f0Sopenharmony_ci} snd_pcm_copy_t; 43d5ac70f0Sopenharmony_ci#endif 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_cistatic int snd_pcm_copy_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) 46d5ac70f0Sopenharmony_ci{ 47d5ac70f0Sopenharmony_ci int err; 48d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 49d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 50d5ac70f0Sopenharmony_ci &access_mask); 51d5ac70f0Sopenharmony_ci if (err < 0) 52d5ac70f0Sopenharmony_ci return err; 53d5ac70f0Sopenharmony_ci params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 54d5ac70f0Sopenharmony_ci return 0; 55d5ac70f0Sopenharmony_ci} 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_cistatic int snd_pcm_copy_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) 58d5ac70f0Sopenharmony_ci{ 59d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 60d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_any(sparams); 61d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 62d5ac70f0Sopenharmony_ci &saccess_mask); 63d5ac70f0Sopenharmony_ci return 0; 64d5ac70f0Sopenharmony_ci} 65d5ac70f0Sopenharmony_ci 66d5ac70f0Sopenharmony_cistatic int snd_pcm_copy_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 67d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 68d5ac70f0Sopenharmony_ci{ 69d5ac70f0Sopenharmony_ci int err; 70d5ac70f0Sopenharmony_ci unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; 71d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(sparams, links, params); 72d5ac70f0Sopenharmony_ci if (err < 0) 73d5ac70f0Sopenharmony_ci return err; 74d5ac70f0Sopenharmony_ci return 0; 75d5ac70f0Sopenharmony_ci} 76d5ac70f0Sopenharmony_ci 77d5ac70f0Sopenharmony_cistatic int snd_pcm_copy_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 78d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 79d5ac70f0Sopenharmony_ci{ 80d5ac70f0Sopenharmony_ci int err; 81d5ac70f0Sopenharmony_ci unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; 82d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(params, links, sparams); 83d5ac70f0Sopenharmony_ci if (err < 0) 84d5ac70f0Sopenharmony_ci return err; 85d5ac70f0Sopenharmony_ci return 0; 86d5ac70f0Sopenharmony_ci} 87d5ac70f0Sopenharmony_ci 88d5ac70f0Sopenharmony_cistatic int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 89d5ac70f0Sopenharmony_ci{ 90d5ac70f0Sopenharmony_ci return snd_pcm_hw_refine_slave(pcm, params, 91d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_cprepare, 92d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_cchange, 93d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_sprepare, 94d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_schange, 95d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_refine); 96d5ac70f0Sopenharmony_ci} 97d5ac70f0Sopenharmony_ci 98d5ac70f0Sopenharmony_cistatic int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 99d5ac70f0Sopenharmony_ci{ 100d5ac70f0Sopenharmony_ci return snd_pcm_hw_params_slave(pcm, params, 101d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_cchange, 102d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_sprepare, 103d5ac70f0Sopenharmony_ci snd_pcm_copy_hw_refine_schange, 104d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_params); 105d5ac70f0Sopenharmony_ci} 106d5ac70f0Sopenharmony_ci 107d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 108d5ac70f0Sopenharmony_cisnd_pcm_copy_write_areas(snd_pcm_t *pcm, 109d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 110d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 111d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 112d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 113d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 114d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 115d5ac70f0Sopenharmony_ci{ 116d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 117d5ac70f0Sopenharmony_ci size = *slave_sizep; 118d5ac70f0Sopenharmony_ci snd_pcm_areas_copy(slave_areas, slave_offset, 119d5ac70f0Sopenharmony_ci areas, offset, 120d5ac70f0Sopenharmony_ci pcm->channels, size, pcm->format); 121d5ac70f0Sopenharmony_ci *slave_sizep = size; 122d5ac70f0Sopenharmony_ci return size; 123d5ac70f0Sopenharmony_ci} 124d5ac70f0Sopenharmony_ci 125d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 126d5ac70f0Sopenharmony_cisnd_pcm_copy_read_areas(snd_pcm_t *pcm, 127d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 128d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 129d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 130d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 131d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 132d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 133d5ac70f0Sopenharmony_ci{ 134d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 135d5ac70f0Sopenharmony_ci size = *slave_sizep; 136d5ac70f0Sopenharmony_ci snd_pcm_areas_copy(areas, offset, 137d5ac70f0Sopenharmony_ci slave_areas, slave_offset, 138d5ac70f0Sopenharmony_ci pcm->channels, size, pcm->format); 139d5ac70f0Sopenharmony_ci *slave_sizep = size; 140d5ac70f0Sopenharmony_ci return size; 141d5ac70f0Sopenharmony_ci} 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_cistatic void snd_pcm_copy_dump(snd_pcm_t *pcm, snd_output_t *out) 144d5ac70f0Sopenharmony_ci{ 145d5ac70f0Sopenharmony_ci snd_pcm_copy_t *copy = pcm->private_data; 146d5ac70f0Sopenharmony_ci snd_output_printf(out, "Copy conversion PCM\n"); 147d5ac70f0Sopenharmony_ci if (pcm->setup) { 148d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 149d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 150d5ac70f0Sopenharmony_ci } 151d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 152d5ac70f0Sopenharmony_ci snd_pcm_dump(copy->plug.gen.slave, out); 153d5ac70f0Sopenharmony_ci} 154d5ac70f0Sopenharmony_ci 155d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_copy_ops = { 156d5ac70f0Sopenharmony_ci .close = snd_pcm_generic_close, 157d5ac70f0Sopenharmony_ci .info = snd_pcm_generic_info, 158d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_copy_hw_refine, 159d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_copy_hw_params, 160d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_generic_hw_free, 161d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_generic_sw_params, 162d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_generic_channel_info, 163d5ac70f0Sopenharmony_ci .dump = snd_pcm_copy_dump, 164d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_generic_nonblock, 165d5ac70f0Sopenharmony_ci .async = snd_pcm_generic_async, 166d5ac70f0Sopenharmony_ci .mmap = snd_pcm_generic_mmap, 167d5ac70f0Sopenharmony_ci .munmap = snd_pcm_generic_munmap, 168d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_generic_query_chmaps, 169d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_generic_get_chmap, 170d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_generic_set_chmap, 171d5ac70f0Sopenharmony_ci}; 172d5ac70f0Sopenharmony_ci 173d5ac70f0Sopenharmony_ci/** 174d5ac70f0Sopenharmony_ci * \brief Creates a new copy PCM 175d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 176d5ac70f0Sopenharmony_ci * \param name Name of PCM 177d5ac70f0Sopenharmony_ci * \param slave Slave PCM handle 178d5ac70f0Sopenharmony_ci * \param close_slave When set, the slave PCM handle is closed with copy PCM 179d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 180d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 181d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 182d5ac70f0Sopenharmony_ci * changed in future. 183d5ac70f0Sopenharmony_ci */ 184d5ac70f0Sopenharmony_ciint snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave) 185d5ac70f0Sopenharmony_ci{ 186d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 187d5ac70f0Sopenharmony_ci snd_pcm_copy_t *copy; 188d5ac70f0Sopenharmony_ci int err; 189d5ac70f0Sopenharmony_ci assert(pcmp && slave); 190d5ac70f0Sopenharmony_ci copy = calloc(1, sizeof(snd_pcm_copy_t)); 191d5ac70f0Sopenharmony_ci if (!copy) { 192d5ac70f0Sopenharmony_ci return -ENOMEM; 193d5ac70f0Sopenharmony_ci } 194d5ac70f0Sopenharmony_ci snd_pcm_plugin_init(©->plug); 195d5ac70f0Sopenharmony_ci copy->plug.read = snd_pcm_copy_read_areas; 196d5ac70f0Sopenharmony_ci copy->plug.write = snd_pcm_copy_write_areas; 197d5ac70f0Sopenharmony_ci copy->plug.undo_read = snd_pcm_plugin_undo_read_generic; 198d5ac70f0Sopenharmony_ci copy->plug.undo_write = snd_pcm_plugin_undo_write_generic; 199d5ac70f0Sopenharmony_ci copy->plug.gen.slave = slave; 200d5ac70f0Sopenharmony_ci copy->plug.gen.close_slave = close_slave; 201d5ac70f0Sopenharmony_ci 202d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_COPY, name, slave->stream, slave->mode); 203d5ac70f0Sopenharmony_ci if (err < 0) { 204d5ac70f0Sopenharmony_ci free(copy); 205d5ac70f0Sopenharmony_ci return err; 206d5ac70f0Sopenharmony_ci } 207d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_copy_ops; 208d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_plugin_fast_ops; 209d5ac70f0Sopenharmony_ci pcm->private_data = copy; 210d5ac70f0Sopenharmony_ci pcm->poll_fd = slave->poll_fd; 211d5ac70f0Sopenharmony_ci pcm->poll_events = slave->poll_events; 212d5ac70f0Sopenharmony_ci pcm->tstamp_type = slave->tstamp_type; 213d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, ©->plug.hw_ptr, -1, 0); 214d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, ©->plug.appl_ptr, -1, 0); 215d5ac70f0Sopenharmony_ci *pcmp = pcm; 216d5ac70f0Sopenharmony_ci 217d5ac70f0Sopenharmony_ci return 0; 218d5ac70f0Sopenharmony_ci} 219d5ac70f0Sopenharmony_ci 220d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 221d5ac70f0Sopenharmony_ci 222d5ac70f0Sopenharmony_ci\section pcm_plugins_copy Plugin: copy 223d5ac70f0Sopenharmony_ci 224d5ac70f0Sopenharmony_ciThis plugin copies samples from master copy PCM to given slave PCM. 225d5ac70f0Sopenharmony_ciThe channel count, format and rate must match for both of them. 226d5ac70f0Sopenharmony_ci 227d5ac70f0Sopenharmony_ci\code 228d5ac70f0Sopenharmony_cipcm.name { 229d5ac70f0Sopenharmony_ci type copy # Copy PCM 230d5ac70f0Sopenharmony_ci slave STR # Slave name 231d5ac70f0Sopenharmony_ci # or 232d5ac70f0Sopenharmony_ci slave { # Slave definition 233d5ac70f0Sopenharmony_ci pcm STR # Slave PCM name 234d5ac70f0Sopenharmony_ci # or 235d5ac70f0Sopenharmony_ci pcm { } # Slave PCM definition 236d5ac70f0Sopenharmony_ci } 237d5ac70f0Sopenharmony_ci} 238d5ac70f0Sopenharmony_ci\endcode 239d5ac70f0Sopenharmony_ci 240d5ac70f0Sopenharmony_ci\subsection pcm_plugins_copy_funcref Function reference 241d5ac70f0Sopenharmony_ci 242d5ac70f0Sopenharmony_ci<UL> 243d5ac70f0Sopenharmony_ci <LI>snd_pcm_copy_open() 244d5ac70f0Sopenharmony_ci <LI>_snd_pcm_copy_open() 245d5ac70f0Sopenharmony_ci</UL> 246d5ac70f0Sopenharmony_ci 247d5ac70f0Sopenharmony_ci*/ 248d5ac70f0Sopenharmony_ci 249d5ac70f0Sopenharmony_ci/** 250d5ac70f0Sopenharmony_ci * \brief Creates a new copy PCM 251d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 252d5ac70f0Sopenharmony_ci * \param name Name of PCM 253d5ac70f0Sopenharmony_ci * \param root Root configuration node 254d5ac70f0Sopenharmony_ci * \param conf Configuration node with copy PCM description 255d5ac70f0Sopenharmony_ci * \param stream Stream type 256d5ac70f0Sopenharmony_ci * \param mode Stream mode 257d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 258d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 259d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 260d5ac70f0Sopenharmony_ci * changed in future. 261d5ac70f0Sopenharmony_ci */ 262d5ac70f0Sopenharmony_ciint _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, 263d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 264d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 265d5ac70f0Sopenharmony_ci{ 266d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 267d5ac70f0Sopenharmony_ci int err; 268d5ac70f0Sopenharmony_ci snd_pcm_t *spcm; 269d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL, *sconf; 270d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 271d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 272d5ac70f0Sopenharmony_ci const char *id; 273d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 274d5ac70f0Sopenharmony_ci continue; 275d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 276d5ac70f0Sopenharmony_ci continue; 277d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 278d5ac70f0Sopenharmony_ci slave = n; 279d5ac70f0Sopenharmony_ci continue; 280d5ac70f0Sopenharmony_ci } 281d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 282d5ac70f0Sopenharmony_ci return -EINVAL; 283d5ac70f0Sopenharmony_ci } 284d5ac70f0Sopenharmony_ci if (!slave) { 285d5ac70f0Sopenharmony_ci SNDERR("slave is not defined"); 286d5ac70f0Sopenharmony_ci return -EINVAL; 287d5ac70f0Sopenharmony_ci } 288d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave, &sconf, 0); 289d5ac70f0Sopenharmony_ci if (err < 0) 290d5ac70f0Sopenharmony_ci return err; 291d5ac70f0Sopenharmony_ci err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 292d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 293d5ac70f0Sopenharmony_ci if (err < 0) 294d5ac70f0Sopenharmony_ci return err; 295d5ac70f0Sopenharmony_ci err = snd_pcm_copy_open(pcmp, name, spcm, 1); 296d5ac70f0Sopenharmony_ci if (err < 0) 297d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 298d5ac70f0Sopenharmony_ci return err; 299d5ac70f0Sopenharmony_ci} 300d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 301d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_copy_open, SND_PCM_DLSYM_VERSION); 302d5ac70f0Sopenharmony_ci#endif 303