1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_linear.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Linear Conversion Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2000-2001 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Linear 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 "plugin_ops.h" 32d5ac70f0Sopenharmony_ci#include "bswap.h" 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ci#ifndef PIC 35d5ac70f0Sopenharmony_ci/* entry for static linking */ 36d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_linear = ""; 37d5ac70f0Sopenharmony_ci#endif 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 40d5ac70f0Sopenharmony_citypedef struct { 41d5ac70f0Sopenharmony_ci /* This field need to be the first */ 42d5ac70f0Sopenharmony_ci snd_pcm_plugin_t plug; 43d5ac70f0Sopenharmony_ci unsigned int use_getput; 44d5ac70f0Sopenharmony_ci unsigned int conv_idx; 45d5ac70f0Sopenharmony_ci unsigned int get_idx, put_idx; 46d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat; 47d5ac70f0Sopenharmony_ci} snd_pcm_linear_t; 48d5ac70f0Sopenharmony_ci#endif 49d5ac70f0Sopenharmony_ci 50d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 51d5ac70f0Sopenharmony_ci 52d5ac70f0Sopenharmony_ciint snd_pcm_linear_convert_index(snd_pcm_format_t src_format, 53d5ac70f0Sopenharmony_ci snd_pcm_format_t dst_format) 54d5ac70f0Sopenharmony_ci{ 55d5ac70f0Sopenharmony_ci int src_endian, dst_endian, sign, src_width, dst_width; 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_ci sign = (snd_pcm_format_signed(src_format) != 58d5ac70f0Sopenharmony_ci snd_pcm_format_signed(dst_format)); 59d5ac70f0Sopenharmony_ci#ifdef SND_LITTLE_ENDIAN 60d5ac70f0Sopenharmony_ci src_endian = snd_pcm_format_big_endian(src_format); 61d5ac70f0Sopenharmony_ci dst_endian = snd_pcm_format_big_endian(dst_format); 62d5ac70f0Sopenharmony_ci#else 63d5ac70f0Sopenharmony_ci src_endian = snd_pcm_format_little_endian(src_format); 64d5ac70f0Sopenharmony_ci dst_endian = snd_pcm_format_little_endian(dst_format); 65d5ac70f0Sopenharmony_ci#endif 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_ci if (src_endian < 0) 68d5ac70f0Sopenharmony_ci src_endian = 0; 69d5ac70f0Sopenharmony_ci if (dst_endian < 0) 70d5ac70f0Sopenharmony_ci dst_endian = 0; 71d5ac70f0Sopenharmony_ci 72d5ac70f0Sopenharmony_ci src_width = snd_pcm_format_width(src_format) / 8 - 1; 73d5ac70f0Sopenharmony_ci dst_width = snd_pcm_format_width(dst_format) / 8 - 1; 74d5ac70f0Sopenharmony_ci 75d5ac70f0Sopenharmony_ci return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; 76d5ac70f0Sopenharmony_ci} 77d5ac70f0Sopenharmony_ci 78d5ac70f0Sopenharmony_ciint snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) 79d5ac70f0Sopenharmony_ci{ 80d5ac70f0Sopenharmony_ci int sign, width, pwidth, endian; 81d5ac70f0Sopenharmony_ci sign = (snd_pcm_format_signed(src_format) != 82d5ac70f0Sopenharmony_ci snd_pcm_format_signed(dst_format)); 83d5ac70f0Sopenharmony_ci#ifdef SND_LITTLE_ENDIAN 84d5ac70f0Sopenharmony_ci endian = snd_pcm_format_big_endian(src_format); 85d5ac70f0Sopenharmony_ci#else 86d5ac70f0Sopenharmony_ci endian = snd_pcm_format_little_endian(src_format); 87d5ac70f0Sopenharmony_ci#endif 88d5ac70f0Sopenharmony_ci if (endian < 0) 89d5ac70f0Sopenharmony_ci endian = 0; 90d5ac70f0Sopenharmony_ci pwidth = snd_pcm_format_physical_width(src_format); 91d5ac70f0Sopenharmony_ci width = snd_pcm_format_width(src_format); 92d5ac70f0Sopenharmony_ci if (pwidth == 24) { 93d5ac70f0Sopenharmony_ci switch (width) { 94d5ac70f0Sopenharmony_ci case 24: 95d5ac70f0Sopenharmony_ci width = 0; break; 96d5ac70f0Sopenharmony_ci case 20: 97d5ac70f0Sopenharmony_ci width = 1; break; 98d5ac70f0Sopenharmony_ci case 18: 99d5ac70f0Sopenharmony_ci default: 100d5ac70f0Sopenharmony_ci width = 2; break; 101d5ac70f0Sopenharmony_ci } 102d5ac70f0Sopenharmony_ci return width * 4 + endian * 2 + sign + 20; 103d5ac70f0Sopenharmony_ci } else { 104d5ac70f0Sopenharmony_ci if (width == 20) 105d5ac70f0Sopenharmony_ci width = 40; 106d5ac70f0Sopenharmony_ci 107d5ac70f0Sopenharmony_ci width = width / 8 - 1; 108d5ac70f0Sopenharmony_ci return width * 4 + endian * 2 + sign; 109d5ac70f0Sopenharmony_ci } 110d5ac70f0Sopenharmony_ci} 111d5ac70f0Sopenharmony_ci 112d5ac70f0Sopenharmony_ciint snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) 113d5ac70f0Sopenharmony_ci{ 114d5ac70f0Sopenharmony_ci int sign, width, pwidth, endian; 115d5ac70f0Sopenharmony_ci sign = (snd_pcm_format_signed(src_format) != 116d5ac70f0Sopenharmony_ci snd_pcm_format_signed(dst_format)); 117d5ac70f0Sopenharmony_ci#ifdef SND_LITTLE_ENDIAN 118d5ac70f0Sopenharmony_ci endian = snd_pcm_format_big_endian(dst_format); 119d5ac70f0Sopenharmony_ci#else 120d5ac70f0Sopenharmony_ci endian = snd_pcm_format_little_endian(dst_format); 121d5ac70f0Sopenharmony_ci#endif 122d5ac70f0Sopenharmony_ci if (endian < 0) 123d5ac70f0Sopenharmony_ci endian = 0; 124d5ac70f0Sopenharmony_ci pwidth = snd_pcm_format_physical_width(dst_format); 125d5ac70f0Sopenharmony_ci width = snd_pcm_format_width(dst_format); 126d5ac70f0Sopenharmony_ci if (pwidth == 24) { 127d5ac70f0Sopenharmony_ci switch (width) { 128d5ac70f0Sopenharmony_ci case 24: 129d5ac70f0Sopenharmony_ci width = 0; break; 130d5ac70f0Sopenharmony_ci case 20: 131d5ac70f0Sopenharmony_ci width = 1; break; 132d5ac70f0Sopenharmony_ci case 18: 133d5ac70f0Sopenharmony_ci default: 134d5ac70f0Sopenharmony_ci width = 2; break; 135d5ac70f0Sopenharmony_ci } 136d5ac70f0Sopenharmony_ci return width * 4 + endian * 2 + sign + 20; 137d5ac70f0Sopenharmony_ci } else { 138d5ac70f0Sopenharmony_ci if (width == 20) 139d5ac70f0Sopenharmony_ci width = 40; 140d5ac70f0Sopenharmony_ci 141d5ac70f0Sopenharmony_ci width = width / 8 - 1; 142d5ac70f0Sopenharmony_ci return width * 4 + endian * 2 + sign; 143d5ac70f0Sopenharmony_ci } 144d5ac70f0Sopenharmony_ci} 145d5ac70f0Sopenharmony_ci 146d5ac70f0Sopenharmony_civoid snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, 147d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, 148d5ac70f0Sopenharmony_ci unsigned int channels, snd_pcm_uframes_t frames, 149d5ac70f0Sopenharmony_ci unsigned int convidx) 150d5ac70f0Sopenharmony_ci{ 151d5ac70f0Sopenharmony_ci#define CONV_LABELS 152d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 153d5ac70f0Sopenharmony_ci#undef CONV_LABELS 154d5ac70f0Sopenharmony_ci void *conv = conv_labels[convidx]; 155d5ac70f0Sopenharmony_ci unsigned int channel; 156d5ac70f0Sopenharmony_ci for (channel = 0; channel < channels; ++channel) { 157d5ac70f0Sopenharmony_ci const char *src; 158d5ac70f0Sopenharmony_ci char *dst; 159d5ac70f0Sopenharmony_ci int src_step, dst_step; 160d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames1; 161d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_area = &src_areas[channel]; 162d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; 163d5ac70f0Sopenharmony_ci src = snd_pcm_channel_area_addr(src_area, src_offset); 164d5ac70f0Sopenharmony_ci dst = snd_pcm_channel_area_addr(dst_area, dst_offset); 165d5ac70f0Sopenharmony_ci src_step = snd_pcm_channel_area_step(src_area); 166d5ac70f0Sopenharmony_ci dst_step = snd_pcm_channel_area_step(dst_area); 167d5ac70f0Sopenharmony_ci frames1 = frames; 168d5ac70f0Sopenharmony_ci while (frames1-- > 0) { 169d5ac70f0Sopenharmony_ci goto *conv; 170d5ac70f0Sopenharmony_ci#define CONV_END after 171d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 172d5ac70f0Sopenharmony_ci#undef CONV_END 173d5ac70f0Sopenharmony_ci after: 174d5ac70f0Sopenharmony_ci src += src_step; 175d5ac70f0Sopenharmony_ci dst += dst_step; 176d5ac70f0Sopenharmony_ci } 177d5ac70f0Sopenharmony_ci } 178d5ac70f0Sopenharmony_ci} 179d5ac70f0Sopenharmony_ci 180d5ac70f0Sopenharmony_civoid snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, 181d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, 182d5ac70f0Sopenharmony_ci unsigned int channels, snd_pcm_uframes_t frames, 183d5ac70f0Sopenharmony_ci unsigned int get_idx, unsigned int put_idx) 184d5ac70f0Sopenharmony_ci{ 185d5ac70f0Sopenharmony_ci#define CONV24_LABELS 186d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 187d5ac70f0Sopenharmony_ci#undef CONV24_LABELS 188d5ac70f0Sopenharmony_ci void *get = get32_labels[get_idx]; 189d5ac70f0Sopenharmony_ci void *put = put32_labels[put_idx]; 190d5ac70f0Sopenharmony_ci unsigned int channel; 191d5ac70f0Sopenharmony_ci uint32_t sample = 0; 192d5ac70f0Sopenharmony_ci for (channel = 0; channel < channels; ++channel) { 193d5ac70f0Sopenharmony_ci const char *src; 194d5ac70f0Sopenharmony_ci char *dst; 195d5ac70f0Sopenharmony_ci int src_step, dst_step; 196d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames1; 197d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_area = &src_areas[channel]; 198d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; 199d5ac70f0Sopenharmony_ci src = snd_pcm_channel_area_addr(src_area, src_offset); 200d5ac70f0Sopenharmony_ci dst = snd_pcm_channel_area_addr(dst_area, dst_offset); 201d5ac70f0Sopenharmony_ci src_step = snd_pcm_channel_area_step(src_area); 202d5ac70f0Sopenharmony_ci dst_step = snd_pcm_channel_area_step(dst_area); 203d5ac70f0Sopenharmony_ci frames1 = frames; 204d5ac70f0Sopenharmony_ci while (frames1-- > 0) { 205d5ac70f0Sopenharmony_ci goto *get; 206d5ac70f0Sopenharmony_ci#define CONV24_END after 207d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 208d5ac70f0Sopenharmony_ci#undef CONV24_END 209d5ac70f0Sopenharmony_ci after: 210d5ac70f0Sopenharmony_ci src += src_step; 211d5ac70f0Sopenharmony_ci dst += dst_step; 212d5ac70f0Sopenharmony_ci } 213d5ac70f0Sopenharmony_ci } 214d5ac70f0Sopenharmony_ci} 215d5ac70f0Sopenharmony_ci 216d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 217d5ac70f0Sopenharmony_ci 218d5ac70f0Sopenharmony_cistatic int snd_pcm_linear_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) 219d5ac70f0Sopenharmony_ci{ 220d5ac70f0Sopenharmony_ci int err; 221d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 222d5ac70f0Sopenharmony_ci snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; 223d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 224d5ac70f0Sopenharmony_ci &access_mask); 225d5ac70f0Sopenharmony_ci if (err < 0) 226d5ac70f0Sopenharmony_ci return err; 227d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, 228d5ac70f0Sopenharmony_ci &format_mask); 229d5ac70f0Sopenharmony_ci if (err < 0) 230d5ac70f0Sopenharmony_ci return err; 231d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); 232d5ac70f0Sopenharmony_ci if (err < 0) 233d5ac70f0Sopenharmony_ci return err; 234d5ac70f0Sopenharmony_ci params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 235d5ac70f0Sopenharmony_ci return 0; 236d5ac70f0Sopenharmony_ci} 237d5ac70f0Sopenharmony_ci 238d5ac70f0Sopenharmony_cistatic int snd_pcm_linear_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) 239d5ac70f0Sopenharmony_ci{ 240d5ac70f0Sopenharmony_ci snd_pcm_linear_t *linear = pcm->private_data; 241d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 242d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_any(sparams); 243d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 244d5ac70f0Sopenharmony_ci &saccess_mask); 245d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_set_format(sparams, linear->sformat); 246d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); 247d5ac70f0Sopenharmony_ci return 0; 248d5ac70f0Sopenharmony_ci} 249d5ac70f0Sopenharmony_ci 250d5ac70f0Sopenharmony_cistatic int snd_pcm_linear_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 251d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 252d5ac70f0Sopenharmony_ci{ 253d5ac70f0Sopenharmony_ci int err; 254d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 255d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_RATE | 256d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 257d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 258d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS | 259d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 260d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 261d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_TICK_TIME); 262d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(sparams, links, params); 263d5ac70f0Sopenharmony_ci if (err < 0) 264d5ac70f0Sopenharmony_ci return err; 265d5ac70f0Sopenharmony_ci return 0; 266d5ac70f0Sopenharmony_ci} 267d5ac70f0Sopenharmony_ci 268d5ac70f0Sopenharmony_cistatic int snd_pcm_linear_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 269d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 270d5ac70f0Sopenharmony_ci{ 271d5ac70f0Sopenharmony_ci int err; 272d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 273d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_RATE | 274d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 275d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 276d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS | 277d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 278d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 279d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_TICK_TIME); 280d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(params, links, sparams); 281d5ac70f0Sopenharmony_ci if (err < 0) 282d5ac70f0Sopenharmony_ci return err; 283d5ac70f0Sopenharmony_ci return 0; 284d5ac70f0Sopenharmony_ci} 285d5ac70f0Sopenharmony_ci 286d5ac70f0Sopenharmony_cistatic int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 287d5ac70f0Sopenharmony_ci{ 288d5ac70f0Sopenharmony_ci return snd_pcm_hw_refine_slave(pcm, params, 289d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_cprepare, 290d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_cchange, 291d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_sprepare, 292d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_schange, 293d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_refine); 294d5ac70f0Sopenharmony_ci} 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_cistatic int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 297d5ac70f0Sopenharmony_ci{ 298d5ac70f0Sopenharmony_ci snd_pcm_linear_t *linear = pcm->private_data; 299d5ac70f0Sopenharmony_ci snd_pcm_format_t format; 300d5ac70f0Sopenharmony_ci int err = snd_pcm_hw_params_slave(pcm, params, 301d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_cchange, 302d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_sprepare, 303d5ac70f0Sopenharmony_ci snd_pcm_linear_hw_refine_schange, 304d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_params); 305d5ac70f0Sopenharmony_ci if (err < 0) 306d5ac70f0Sopenharmony_ci return err; 307d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); 308d5ac70f0Sopenharmony_ci if (err < 0) 309d5ac70f0Sopenharmony_ci return err; 310d5ac70f0Sopenharmony_ci linear->use_getput = (snd_pcm_format_physical_width(format) == 24 || 311d5ac70f0Sopenharmony_ci snd_pcm_format_physical_width(linear->sformat) == 24 || 312d5ac70f0Sopenharmony_ci snd_pcm_format_width(format) == 20 || 313d5ac70f0Sopenharmony_ci snd_pcm_format_width(linear->sformat) == 20); 314d5ac70f0Sopenharmony_ci if (linear->use_getput) { 315d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 316d5ac70f0Sopenharmony_ci linear->get_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32); 317d5ac70f0Sopenharmony_ci linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, linear->sformat); 318d5ac70f0Sopenharmony_ci } else { 319d5ac70f0Sopenharmony_ci linear->get_idx = snd_pcm_linear_get_index(linear->sformat, SND_PCM_FORMAT_S32); 320d5ac70f0Sopenharmony_ci linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, format); 321d5ac70f0Sopenharmony_ci } 322d5ac70f0Sopenharmony_ci } else { 323d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 324d5ac70f0Sopenharmony_ci linear->conv_idx = snd_pcm_linear_convert_index(format, 325d5ac70f0Sopenharmony_ci linear->sformat); 326d5ac70f0Sopenharmony_ci else 327d5ac70f0Sopenharmony_ci linear->conv_idx = snd_pcm_linear_convert_index(linear->sformat, 328d5ac70f0Sopenharmony_ci format); 329d5ac70f0Sopenharmony_ci } 330d5ac70f0Sopenharmony_ci return 0; 331d5ac70f0Sopenharmony_ci} 332d5ac70f0Sopenharmony_ci 333d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 334d5ac70f0Sopenharmony_cisnd_pcm_linear_write_areas(snd_pcm_t *pcm, 335d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 336d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 337d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 338d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 339d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 340d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 341d5ac70f0Sopenharmony_ci{ 342d5ac70f0Sopenharmony_ci snd_pcm_linear_t *linear = pcm->private_data; 343d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 344d5ac70f0Sopenharmony_ci size = *slave_sizep; 345d5ac70f0Sopenharmony_ci if (linear->use_getput) 346d5ac70f0Sopenharmony_ci snd_pcm_linear_getput(slave_areas, slave_offset, 347d5ac70f0Sopenharmony_ci areas, offset, 348d5ac70f0Sopenharmony_ci pcm->channels, size, 349d5ac70f0Sopenharmony_ci linear->get_idx, linear->put_idx); 350d5ac70f0Sopenharmony_ci else 351d5ac70f0Sopenharmony_ci snd_pcm_linear_convert(slave_areas, slave_offset, 352d5ac70f0Sopenharmony_ci areas, offset, 353d5ac70f0Sopenharmony_ci pcm->channels, size, linear->conv_idx); 354d5ac70f0Sopenharmony_ci *slave_sizep = size; 355d5ac70f0Sopenharmony_ci return size; 356d5ac70f0Sopenharmony_ci} 357d5ac70f0Sopenharmony_ci 358d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 359d5ac70f0Sopenharmony_cisnd_pcm_linear_read_areas(snd_pcm_t *pcm, 360d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 361d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 362d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 363d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 364d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 365d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 366d5ac70f0Sopenharmony_ci{ 367d5ac70f0Sopenharmony_ci snd_pcm_linear_t *linear = pcm->private_data; 368d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 369d5ac70f0Sopenharmony_ci size = *slave_sizep; 370d5ac70f0Sopenharmony_ci if (linear->use_getput) 371d5ac70f0Sopenharmony_ci snd_pcm_linear_getput(areas, offset, 372d5ac70f0Sopenharmony_ci slave_areas, slave_offset, 373d5ac70f0Sopenharmony_ci pcm->channels, size, 374d5ac70f0Sopenharmony_ci linear->get_idx, linear->put_idx); 375d5ac70f0Sopenharmony_ci else 376d5ac70f0Sopenharmony_ci snd_pcm_linear_convert(areas, offset, 377d5ac70f0Sopenharmony_ci slave_areas, slave_offset, 378d5ac70f0Sopenharmony_ci pcm->channels, size, linear->conv_idx); 379d5ac70f0Sopenharmony_ci *slave_sizep = size; 380d5ac70f0Sopenharmony_ci return size; 381d5ac70f0Sopenharmony_ci} 382d5ac70f0Sopenharmony_ci 383d5ac70f0Sopenharmony_cistatic void snd_pcm_linear_dump(snd_pcm_t *pcm, snd_output_t *out) 384d5ac70f0Sopenharmony_ci{ 385d5ac70f0Sopenharmony_ci snd_pcm_linear_t *linear = pcm->private_data; 386d5ac70f0Sopenharmony_ci snd_output_printf(out, "Linear conversion PCM (%s)\n", 387d5ac70f0Sopenharmony_ci snd_pcm_format_name(linear->sformat)); 388d5ac70f0Sopenharmony_ci if (pcm->setup) { 389d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 390d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 391d5ac70f0Sopenharmony_ci } 392d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 393d5ac70f0Sopenharmony_ci snd_pcm_dump(linear->plug.gen.slave, out); 394d5ac70f0Sopenharmony_ci} 395d5ac70f0Sopenharmony_ci 396d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_linear_ops = { 397d5ac70f0Sopenharmony_ci .close = snd_pcm_generic_close, 398d5ac70f0Sopenharmony_ci .info = snd_pcm_generic_info, 399d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_linear_hw_refine, 400d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_linear_hw_params, 401d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_generic_hw_free, 402d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_generic_sw_params, 403d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_generic_channel_info, 404d5ac70f0Sopenharmony_ci .dump = snd_pcm_linear_dump, 405d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_generic_nonblock, 406d5ac70f0Sopenharmony_ci .async = snd_pcm_generic_async, 407d5ac70f0Sopenharmony_ci .mmap = snd_pcm_generic_mmap, 408d5ac70f0Sopenharmony_ci .munmap = snd_pcm_generic_munmap, 409d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_generic_query_chmaps, 410d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_generic_get_chmap, 411d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_generic_set_chmap, 412d5ac70f0Sopenharmony_ci}; 413d5ac70f0Sopenharmony_ci 414d5ac70f0Sopenharmony_ci 415d5ac70f0Sopenharmony_ci/** 416d5ac70f0Sopenharmony_ci * \brief Creates a new linear conversion PCM 417d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 418d5ac70f0Sopenharmony_ci * \param name Name of PCM 419d5ac70f0Sopenharmony_ci * \param sformat Slave (destination) format 420d5ac70f0Sopenharmony_ci * \param slave Slave PCM handle 421d5ac70f0Sopenharmony_ci * \param close_slave When set, the slave PCM handle is closed with copy PCM 422d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 423d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 424d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 425d5ac70f0Sopenharmony_ci * changed in future. 426d5ac70f0Sopenharmony_ci */ 427d5ac70f0Sopenharmony_ciint snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) 428d5ac70f0Sopenharmony_ci{ 429d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 430d5ac70f0Sopenharmony_ci snd_pcm_linear_t *linear; 431d5ac70f0Sopenharmony_ci int err; 432d5ac70f0Sopenharmony_ci assert(pcmp && slave); 433d5ac70f0Sopenharmony_ci if (snd_pcm_format_linear(sformat) != 1) 434d5ac70f0Sopenharmony_ci return -EINVAL; 435d5ac70f0Sopenharmony_ci linear = calloc(1, sizeof(snd_pcm_linear_t)); 436d5ac70f0Sopenharmony_ci if (!linear) { 437d5ac70f0Sopenharmony_ci return -ENOMEM; 438d5ac70f0Sopenharmony_ci } 439d5ac70f0Sopenharmony_ci snd_pcm_plugin_init(&linear->plug); 440d5ac70f0Sopenharmony_ci linear->sformat = sformat; 441d5ac70f0Sopenharmony_ci linear->plug.read = snd_pcm_linear_read_areas; 442d5ac70f0Sopenharmony_ci linear->plug.write = snd_pcm_linear_write_areas; 443d5ac70f0Sopenharmony_ci linear->plug.undo_read = snd_pcm_plugin_undo_read_generic; 444d5ac70f0Sopenharmony_ci linear->plug.undo_write = snd_pcm_plugin_undo_write_generic; 445d5ac70f0Sopenharmony_ci linear->plug.gen.slave = slave; 446d5ac70f0Sopenharmony_ci linear->plug.gen.close_slave = close_slave; 447d5ac70f0Sopenharmony_ci 448d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_LINEAR, name, slave->stream, slave->mode); 449d5ac70f0Sopenharmony_ci if (err < 0) { 450d5ac70f0Sopenharmony_ci free(linear); 451d5ac70f0Sopenharmony_ci return err; 452d5ac70f0Sopenharmony_ci } 453d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_linear_ops; 454d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_plugin_fast_ops; 455d5ac70f0Sopenharmony_ci pcm->private_data = linear; 456d5ac70f0Sopenharmony_ci pcm->poll_fd = slave->poll_fd; 457d5ac70f0Sopenharmony_ci pcm->poll_events = slave->poll_events; 458d5ac70f0Sopenharmony_ci pcm->tstamp_type = slave->tstamp_type; 459d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0); 460d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0); 461d5ac70f0Sopenharmony_ci *pcmp = pcm; 462d5ac70f0Sopenharmony_ci 463d5ac70f0Sopenharmony_ci return 0; 464d5ac70f0Sopenharmony_ci} 465d5ac70f0Sopenharmony_ci 466d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 467d5ac70f0Sopenharmony_ci 468d5ac70f0Sopenharmony_ci\section pcm_plugins_linear Plugin: linear 469d5ac70f0Sopenharmony_ci 470d5ac70f0Sopenharmony_ciThis plugin converts linear samples from master linear conversion PCM to given 471d5ac70f0Sopenharmony_cislave PCM. The channel count, format and rate must match for both of them. 472d5ac70f0Sopenharmony_ci 473d5ac70f0Sopenharmony_ci\code 474d5ac70f0Sopenharmony_cipcm.name { 475d5ac70f0Sopenharmony_ci type linear # Linear conversion PCM 476d5ac70f0Sopenharmony_ci slave STR # Slave name 477d5ac70f0Sopenharmony_ci # or 478d5ac70f0Sopenharmony_ci slave { # Slave definition 479d5ac70f0Sopenharmony_ci pcm STR # Slave PCM name 480d5ac70f0Sopenharmony_ci # or 481d5ac70f0Sopenharmony_ci pcm { } # Slave PCM definition 482d5ac70f0Sopenharmony_ci format STR # Slave format 483d5ac70f0Sopenharmony_ci } 484d5ac70f0Sopenharmony_ci} 485d5ac70f0Sopenharmony_ci\endcode 486d5ac70f0Sopenharmony_ci 487d5ac70f0Sopenharmony_ci\subsection pcm_plugins_linear_funcref Function reference 488d5ac70f0Sopenharmony_ci 489d5ac70f0Sopenharmony_ci<UL> 490d5ac70f0Sopenharmony_ci <LI>snd_pcm_linear_open() 491d5ac70f0Sopenharmony_ci <LI>_snd_pcm_linear_open() 492d5ac70f0Sopenharmony_ci</UL> 493d5ac70f0Sopenharmony_ci 494d5ac70f0Sopenharmony_ci*/ 495d5ac70f0Sopenharmony_ci 496d5ac70f0Sopenharmony_ci/** 497d5ac70f0Sopenharmony_ci * \brief Creates a new linear conversion PCM 498d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 499d5ac70f0Sopenharmony_ci * \param name Name of PCM 500d5ac70f0Sopenharmony_ci * \param root Root configuration node 501d5ac70f0Sopenharmony_ci * \param conf Configuration node with copy PCM description 502d5ac70f0Sopenharmony_ci * \param stream Stream type 503d5ac70f0Sopenharmony_ci * \param mode Stream mode 504d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 505d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 506d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 507d5ac70f0Sopenharmony_ci * changed in future. 508d5ac70f0Sopenharmony_ci */ 509d5ac70f0Sopenharmony_ciint _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, 510d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 511d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 512d5ac70f0Sopenharmony_ci{ 513d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 514d5ac70f0Sopenharmony_ci int err; 515d5ac70f0Sopenharmony_ci snd_pcm_t *spcm; 516d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL, *sconf; 517d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat; 518d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 519d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 520d5ac70f0Sopenharmony_ci const char *id; 521d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 522d5ac70f0Sopenharmony_ci continue; 523d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 524d5ac70f0Sopenharmony_ci continue; 525d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 526d5ac70f0Sopenharmony_ci slave = n; 527d5ac70f0Sopenharmony_ci continue; 528d5ac70f0Sopenharmony_ci } 529d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 530d5ac70f0Sopenharmony_ci return -EINVAL; 531d5ac70f0Sopenharmony_ci } 532d5ac70f0Sopenharmony_ci if (!slave) { 533d5ac70f0Sopenharmony_ci SNDERR("slave is not defined"); 534d5ac70f0Sopenharmony_ci return -EINVAL; 535d5ac70f0Sopenharmony_ci } 536d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave, &sconf, 1, 537d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); 538d5ac70f0Sopenharmony_ci if (err < 0) 539d5ac70f0Sopenharmony_ci return err; 540d5ac70f0Sopenharmony_ci if (snd_pcm_format_linear(sformat) != 1) { 541d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 542d5ac70f0Sopenharmony_ci SNDERR("slave format is not linear"); 543d5ac70f0Sopenharmony_ci return -EINVAL; 544d5ac70f0Sopenharmony_ci } 545d5ac70f0Sopenharmony_ci err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 546d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 547d5ac70f0Sopenharmony_ci if (err < 0) 548d5ac70f0Sopenharmony_ci return err; 549d5ac70f0Sopenharmony_ci err = snd_pcm_linear_open(pcmp, name, sformat, spcm, 1); 550d5ac70f0Sopenharmony_ci if (err < 0) 551d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 552d5ac70f0Sopenharmony_ci return err; 553d5ac70f0Sopenharmony_ci} 554d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 555d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_linear_open, SND_PCM_DLSYM_VERSION); 556d5ac70f0Sopenharmony_ci#endif 557