1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_route.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Route & Volume Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2000-2001 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Route & Volume 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 "plugin_ops.h" 32d5ac70f0Sopenharmony_ci#include "bswap.h" 33d5ac70f0Sopenharmony_ci#include <math.h> 34d5ac70f0Sopenharmony_ci 35d5ac70f0Sopenharmony_ci#ifndef PIC 36d5ac70f0Sopenharmony_ci/* entry for static linking */ 37d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_route = ""; 38d5ac70f0Sopenharmony_ci#endif 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 41d5ac70f0Sopenharmony_ci 42d5ac70f0Sopenharmony_ci/* The best possible hack to support missing optimization in gcc 2.7.2.3 */ 43d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_RESOLUTION & (SND_PCM_PLUGIN_ROUTE_RESOLUTION - 1) != 0 44d5ac70f0Sopenharmony_ci#define div(a) a /= SND_PCM_PLUGIN_ROUTE_RESOLUTION 45d5ac70f0Sopenharmony_ci#elif SND_PCM_PLUGIN_ROUTE_RESOLUTION == 16 46d5ac70f0Sopenharmony_ci#define div(a) a >>= 4 47d5ac70f0Sopenharmony_ci#else 48d5ac70f0Sopenharmony_ci#error "Add some code here" 49d5ac70f0Sopenharmony_ci#endif 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_citypedef struct { 52d5ac70f0Sopenharmony_ci int channel; 53d5ac70f0Sopenharmony_ci int as_int; 54d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 55d5ac70f0Sopenharmony_ci float as_float; 56d5ac70f0Sopenharmony_ci#endif 57d5ac70f0Sopenharmony_ci} snd_pcm_route_ttable_src_t; 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_citypedef struct snd_pcm_route_ttable_dst snd_pcm_route_ttable_dst_t; 60d5ac70f0Sopenharmony_ci 61d5ac70f0Sopenharmony_citypedef struct { 62d5ac70f0Sopenharmony_ci enum {UINT64, FLOAT} sum_idx; 63d5ac70f0Sopenharmony_ci unsigned int get_idx; 64d5ac70f0Sopenharmony_ci unsigned int put_idx; 65d5ac70f0Sopenharmony_ci unsigned int conv_idx; 66d5ac70f0Sopenharmony_ci int use_getput; 67d5ac70f0Sopenharmony_ci unsigned int src_size; 68d5ac70f0Sopenharmony_ci snd_pcm_format_t dst_sfmt; 69d5ac70f0Sopenharmony_ci unsigned int nsrcs; 70d5ac70f0Sopenharmony_ci unsigned int ndsts; 71d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_dst_t *dsts; 72d5ac70f0Sopenharmony_ci} snd_pcm_route_params_t; 73d5ac70f0Sopenharmony_ci 74d5ac70f0Sopenharmony_ci 75d5ac70f0Sopenharmony_citypedef void (*route_f)(const snd_pcm_channel_area_t *dst_area, 76d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_offset, 77d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 78d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_offset, 79d5ac70f0Sopenharmony_ci unsigned int src_channels, 80d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames, 81d5ac70f0Sopenharmony_ci const snd_pcm_route_ttable_dst_t *ttable, 82d5ac70f0Sopenharmony_ci const snd_pcm_route_params_t *params); 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_cistruct snd_pcm_route_ttable_dst { 85d5ac70f0Sopenharmony_ci int att; /* Attenuated */ 86d5ac70f0Sopenharmony_ci unsigned int nsrcs; 87d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_src_t* srcs; 88d5ac70f0Sopenharmony_ci route_f func; 89d5ac70f0Sopenharmony_ci}; 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_citypedef union { 92d5ac70f0Sopenharmony_ci int32_t as_sint32; 93d5ac70f0Sopenharmony_ci int64_t as_sint64; 94d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 95d5ac70f0Sopenharmony_ci float as_float; 96d5ac70f0Sopenharmony_ci#endif 97d5ac70f0Sopenharmony_ci} sum_t; 98d5ac70f0Sopenharmony_ci 99d5ac70f0Sopenharmony_citypedef struct { 100d5ac70f0Sopenharmony_ci /* This field need to be the first */ 101d5ac70f0Sopenharmony_ci snd_pcm_plugin_t plug; 102d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat; 103d5ac70f0Sopenharmony_ci int schannels; 104d5ac70f0Sopenharmony_ci snd_pcm_route_params_t params; 105d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *chmap; 106d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **chmap_override; 107d5ac70f0Sopenharmony_ci} snd_pcm_route_t; 108d5ac70f0Sopenharmony_ci 109d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 110d5ac70f0Sopenharmony_ci 111d5ac70f0Sopenharmony_cistatic void snd_pcm_route_convert1_zero(const snd_pcm_channel_area_t *dst_area, 112d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_offset, 113d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas ATTRIBUTE_UNUSED, 114d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_offset ATTRIBUTE_UNUSED, 115d5ac70f0Sopenharmony_ci unsigned int src_channels ATTRIBUTE_UNUSED, 116d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames, 117d5ac70f0Sopenharmony_ci const snd_pcm_route_ttable_dst_t* ttable ATTRIBUTE_UNUSED, 118d5ac70f0Sopenharmony_ci const snd_pcm_route_params_t *params) 119d5ac70f0Sopenharmony_ci{ 120d5ac70f0Sopenharmony_ci snd_pcm_area_silence(dst_area, dst_offset, frames, params->dst_sfmt); 121d5ac70f0Sopenharmony_ci} 122d5ac70f0Sopenharmony_ci 123d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 124d5ac70f0Sopenharmony_ci 125d5ac70f0Sopenharmony_cistatic void snd_pcm_route_convert1_one(const snd_pcm_channel_area_t *dst_area, 126d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_offset, 127d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 128d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_offset, 129d5ac70f0Sopenharmony_ci unsigned int src_channels, 130d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames, 131d5ac70f0Sopenharmony_ci const snd_pcm_route_ttable_dst_t* ttable, 132d5ac70f0Sopenharmony_ci const snd_pcm_route_params_t *params) 133d5ac70f0Sopenharmony_ci{ 134d5ac70f0Sopenharmony_ci#define CONV_LABELS 135d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 136d5ac70f0Sopenharmony_ci#undef CONV_LABELS 137d5ac70f0Sopenharmony_ci void *conv; 138d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_area = 0; 139d5ac70f0Sopenharmony_ci unsigned int srcidx; 140d5ac70f0Sopenharmony_ci const char *src; 141d5ac70f0Sopenharmony_ci char *dst; 142d5ac70f0Sopenharmony_ci int src_step, dst_step; 143d5ac70f0Sopenharmony_ci for (srcidx = 0; srcidx < ttable->nsrcs && srcidx < src_channels; ++srcidx) { 144d5ac70f0Sopenharmony_ci unsigned int channel = ttable->srcs[srcidx].channel; 145d5ac70f0Sopenharmony_ci if (channel >= src_channels) 146d5ac70f0Sopenharmony_ci continue; 147d5ac70f0Sopenharmony_ci src_area = &src_areas[channel]; 148d5ac70f0Sopenharmony_ci if (src_area->addr != NULL) 149d5ac70f0Sopenharmony_ci break; 150d5ac70f0Sopenharmony_ci } 151d5ac70f0Sopenharmony_ci if (srcidx == ttable->nsrcs || srcidx == src_channels) { 152d5ac70f0Sopenharmony_ci snd_pcm_route_convert1_zero(dst_area, dst_offset, 153d5ac70f0Sopenharmony_ci src_areas, src_offset, 154d5ac70f0Sopenharmony_ci src_channels, 155d5ac70f0Sopenharmony_ci frames, ttable, params); 156d5ac70f0Sopenharmony_ci return; 157d5ac70f0Sopenharmony_ci } 158d5ac70f0Sopenharmony_ci 159d5ac70f0Sopenharmony_ci conv = conv_labels[params->conv_idx]; 160d5ac70f0Sopenharmony_ci src = snd_pcm_channel_area_addr(src_area, src_offset); 161d5ac70f0Sopenharmony_ci dst = snd_pcm_channel_area_addr(dst_area, dst_offset); 162d5ac70f0Sopenharmony_ci src_step = snd_pcm_channel_area_step(src_area); 163d5ac70f0Sopenharmony_ci dst_step = snd_pcm_channel_area_step(dst_area); 164d5ac70f0Sopenharmony_ci while (frames-- > 0) { 165d5ac70f0Sopenharmony_ci goto *conv; 166d5ac70f0Sopenharmony_ci#define CONV_END after 167d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 168d5ac70f0Sopenharmony_ci#undef CONV_END 169d5ac70f0Sopenharmony_ci after: 170d5ac70f0Sopenharmony_ci src += src_step; 171d5ac70f0Sopenharmony_ci dst += dst_step; 172d5ac70f0Sopenharmony_ci } 173d5ac70f0Sopenharmony_ci} 174d5ac70f0Sopenharmony_ci 175d5ac70f0Sopenharmony_cistatic void snd_pcm_route_convert1_one_getput(const snd_pcm_channel_area_t *dst_area, 176d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_offset, 177d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 178d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_offset, 179d5ac70f0Sopenharmony_ci unsigned int src_channels, 180d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames, 181d5ac70f0Sopenharmony_ci const snd_pcm_route_ttable_dst_t* ttable, 182d5ac70f0Sopenharmony_ci const snd_pcm_route_params_t *params) 183d5ac70f0Sopenharmony_ci{ 184d5ac70f0Sopenharmony_ci#define CONV24_LABELS 185d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 186d5ac70f0Sopenharmony_ci#undef CONV24_LABELS 187d5ac70f0Sopenharmony_ci void *get, *put; 188d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_area = 0; 189d5ac70f0Sopenharmony_ci unsigned int srcidx; 190d5ac70f0Sopenharmony_ci const char *src; 191d5ac70f0Sopenharmony_ci char *dst; 192d5ac70f0Sopenharmony_ci int src_step, dst_step; 193d5ac70f0Sopenharmony_ci uint32_t sample = 0; 194d5ac70f0Sopenharmony_ci for (srcidx = 0; srcidx < ttable->nsrcs && srcidx < src_channels; ++srcidx) { 195d5ac70f0Sopenharmony_ci unsigned int channel = ttable->srcs[srcidx].channel; 196d5ac70f0Sopenharmony_ci if (channel >= src_channels) 197d5ac70f0Sopenharmony_ci continue; 198d5ac70f0Sopenharmony_ci src_area = &src_areas[channel]; 199d5ac70f0Sopenharmony_ci if (src_area->addr != NULL) 200d5ac70f0Sopenharmony_ci break; 201d5ac70f0Sopenharmony_ci } 202d5ac70f0Sopenharmony_ci if (srcidx == ttable->nsrcs || srcidx == src_channels) { 203d5ac70f0Sopenharmony_ci snd_pcm_route_convert1_zero(dst_area, dst_offset, 204d5ac70f0Sopenharmony_ci src_areas, src_offset, 205d5ac70f0Sopenharmony_ci src_channels, 206d5ac70f0Sopenharmony_ci frames, ttable, params); 207d5ac70f0Sopenharmony_ci return; 208d5ac70f0Sopenharmony_ci } 209d5ac70f0Sopenharmony_ci 210d5ac70f0Sopenharmony_ci get = get32_labels[params->get_idx]; 211d5ac70f0Sopenharmony_ci put = put32_labels[params->put_idx]; 212d5ac70f0Sopenharmony_ci src = snd_pcm_channel_area_addr(src_area, src_offset); 213d5ac70f0Sopenharmony_ci dst = snd_pcm_channel_area_addr(dst_area, dst_offset); 214d5ac70f0Sopenharmony_ci src_step = snd_pcm_channel_area_step(src_area); 215d5ac70f0Sopenharmony_ci dst_step = snd_pcm_channel_area_step(dst_area); 216d5ac70f0Sopenharmony_ci while (frames-- > 0) { 217d5ac70f0Sopenharmony_ci goto *get; 218d5ac70f0Sopenharmony_ci#define CONV24_END after 219d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 220d5ac70f0Sopenharmony_ci#undef CONV24_END 221d5ac70f0Sopenharmony_ci after: 222d5ac70f0Sopenharmony_ci src += src_step; 223d5ac70f0Sopenharmony_ci dst += dst_step; 224d5ac70f0Sopenharmony_ci } 225d5ac70f0Sopenharmony_ci} 226d5ac70f0Sopenharmony_ci 227d5ac70f0Sopenharmony_cistatic void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, 228d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_offset, 229d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 230d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_offset, 231d5ac70f0Sopenharmony_ci unsigned int src_channels, 232d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames, 233d5ac70f0Sopenharmony_ci const snd_pcm_route_ttable_dst_t* ttable, 234d5ac70f0Sopenharmony_ci const snd_pcm_route_params_t *params) 235d5ac70f0Sopenharmony_ci{ 236d5ac70f0Sopenharmony_ci#define GET32_LABELS 237d5ac70f0Sopenharmony_ci#define PUT32_LABELS 238d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 239d5ac70f0Sopenharmony_ci#undef GET32_LABELS 240d5ac70f0Sopenharmony_ci#undef PUT32_LABELS 241d5ac70f0Sopenharmony_ci static void *const zero_labels[2] = { 242d5ac70f0Sopenharmony_ci &&zero_int64, 243d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 244d5ac70f0Sopenharmony_ci &&zero_float 245d5ac70f0Sopenharmony_ci#endif 246d5ac70f0Sopenharmony_ci }; 247d5ac70f0Sopenharmony_ci /* sum_type att */ 248d5ac70f0Sopenharmony_ci static void *const add_labels[2 * 2] = { 249d5ac70f0Sopenharmony_ci &&add_int64_noatt, &&add_int64_att, 250d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 251d5ac70f0Sopenharmony_ci &&add_float_noatt, &&add_float_att 252d5ac70f0Sopenharmony_ci#endif 253d5ac70f0Sopenharmony_ci }; 254d5ac70f0Sopenharmony_ci /* sum_type att */ 255d5ac70f0Sopenharmony_ci static void *const norm_labels[2 * 2] = { 256d5ac70f0Sopenharmony_ci &&norm_int64_noatt, 257d5ac70f0Sopenharmony_ci &&norm_int64_att, 258d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 259d5ac70f0Sopenharmony_ci &&norm_float, 260d5ac70f0Sopenharmony_ci &&norm_float, 261d5ac70f0Sopenharmony_ci#endif 262d5ac70f0Sopenharmony_ci }; 263d5ac70f0Sopenharmony_ci void *zero, *get32, *add, *norm, *put32; 264d5ac70f0Sopenharmony_ci int nsrcs = ttable->nsrcs; 265d5ac70f0Sopenharmony_ci char *dst; 266d5ac70f0Sopenharmony_ci int dst_step; 267d5ac70f0Sopenharmony_ci const char *srcs[nsrcs]; 268d5ac70f0Sopenharmony_ci int src_steps[nsrcs]; 269d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_src_t src_tt[nsrcs]; 270d5ac70f0Sopenharmony_ci int32_t sample = 0; 271d5ac70f0Sopenharmony_ci int srcidx, srcidx1 = 0; 272d5ac70f0Sopenharmony_ci for (srcidx = 0; srcidx < nsrcs && (unsigned)srcidx < src_channels; ++srcidx) { 273d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_area; 274d5ac70f0Sopenharmony_ci unsigned int channel = ttable->srcs[srcidx].channel; 275d5ac70f0Sopenharmony_ci if (channel >= src_channels) 276d5ac70f0Sopenharmony_ci continue; 277d5ac70f0Sopenharmony_ci src_area = &src_areas[channel]; 278d5ac70f0Sopenharmony_ci srcs[srcidx1] = snd_pcm_channel_area_addr(src_area, src_offset); 279d5ac70f0Sopenharmony_ci src_steps[srcidx1] = snd_pcm_channel_area_step(src_area); 280d5ac70f0Sopenharmony_ci src_tt[srcidx1] = ttable->srcs[srcidx]; 281d5ac70f0Sopenharmony_ci srcidx1++; 282d5ac70f0Sopenharmony_ci } 283d5ac70f0Sopenharmony_ci nsrcs = srcidx1; 284d5ac70f0Sopenharmony_ci if (nsrcs == 0) { 285d5ac70f0Sopenharmony_ci snd_pcm_route_convert1_zero(dst_area, dst_offset, 286d5ac70f0Sopenharmony_ci src_areas, src_offset, 287d5ac70f0Sopenharmony_ci src_channels, 288d5ac70f0Sopenharmony_ci frames, ttable, params); 289d5ac70f0Sopenharmony_ci return; 290d5ac70f0Sopenharmony_ci } else if (nsrcs == 1 && src_tt[0].as_int == SND_PCM_PLUGIN_ROUTE_RESOLUTION) { 291d5ac70f0Sopenharmony_ci if (params->use_getput) 292d5ac70f0Sopenharmony_ci snd_pcm_route_convert1_one_getput(dst_area, dst_offset, 293d5ac70f0Sopenharmony_ci src_areas, src_offset, 294d5ac70f0Sopenharmony_ci src_channels, 295d5ac70f0Sopenharmony_ci frames, ttable, params); 296d5ac70f0Sopenharmony_ci else 297d5ac70f0Sopenharmony_ci snd_pcm_route_convert1_one(dst_area, dst_offset, 298d5ac70f0Sopenharmony_ci src_areas, src_offset, 299d5ac70f0Sopenharmony_ci src_channels, 300d5ac70f0Sopenharmony_ci frames, ttable, params); 301d5ac70f0Sopenharmony_ci return; 302d5ac70f0Sopenharmony_ci } 303d5ac70f0Sopenharmony_ci 304d5ac70f0Sopenharmony_ci zero = zero_labels[params->sum_idx]; 305d5ac70f0Sopenharmony_ci get32 = get32_labels[params->get_idx]; 306d5ac70f0Sopenharmony_ci add = add_labels[params->sum_idx * 2 + ttable->att]; 307d5ac70f0Sopenharmony_ci norm = norm_labels[params->sum_idx * 2 + ttable->att]; 308d5ac70f0Sopenharmony_ci put32 = put32_labels[params->put_idx]; 309d5ac70f0Sopenharmony_ci dst = snd_pcm_channel_area_addr(dst_area, dst_offset); 310d5ac70f0Sopenharmony_ci dst_step = snd_pcm_channel_area_step(dst_area); 311d5ac70f0Sopenharmony_ci 312d5ac70f0Sopenharmony_ci while (frames-- > 0) { 313d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_src_t *ttp = src_tt; 314d5ac70f0Sopenharmony_ci sum_t sum; 315d5ac70f0Sopenharmony_ci 316d5ac70f0Sopenharmony_ci /* Zero sum */ 317d5ac70f0Sopenharmony_ci goto *zero; 318d5ac70f0Sopenharmony_ci zero_int64: 319d5ac70f0Sopenharmony_ci sum.as_sint64 = 0; 320d5ac70f0Sopenharmony_ci goto zero_end; 321d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 322d5ac70f0Sopenharmony_ci zero_float: 323d5ac70f0Sopenharmony_ci sum.as_float = 0.0; 324d5ac70f0Sopenharmony_ci goto zero_end; 325d5ac70f0Sopenharmony_ci#endif 326d5ac70f0Sopenharmony_ci zero_end: 327d5ac70f0Sopenharmony_ci for (srcidx = 0; srcidx < nsrcs; ++srcidx) { 328d5ac70f0Sopenharmony_ci const char *src = srcs[srcidx]; 329d5ac70f0Sopenharmony_ci 330d5ac70f0Sopenharmony_ci /* Get sample */ 331d5ac70f0Sopenharmony_ci goto *get32; 332d5ac70f0Sopenharmony_ci#define GET32_END after_get 333d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 334d5ac70f0Sopenharmony_ci#undef GET32_END 335d5ac70f0Sopenharmony_ci after_get: 336d5ac70f0Sopenharmony_ci 337d5ac70f0Sopenharmony_ci /* Sum */ 338d5ac70f0Sopenharmony_ci goto *add; 339d5ac70f0Sopenharmony_ci add_int64_att: 340d5ac70f0Sopenharmony_ci sum.as_sint64 += (int64_t) sample * ttp->as_int; 341d5ac70f0Sopenharmony_ci goto after_sum; 342d5ac70f0Sopenharmony_ci add_int64_noatt: 343d5ac70f0Sopenharmony_ci if (ttp->as_int) 344d5ac70f0Sopenharmony_ci sum.as_sint64 += sample; 345d5ac70f0Sopenharmony_ci goto after_sum; 346d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 347d5ac70f0Sopenharmony_ci add_float_att: 348d5ac70f0Sopenharmony_ci sum.as_float += sample * ttp->as_float; 349d5ac70f0Sopenharmony_ci goto after_sum; 350d5ac70f0Sopenharmony_ci add_float_noatt: 351d5ac70f0Sopenharmony_ci if (ttp->as_int) 352d5ac70f0Sopenharmony_ci sum.as_float += sample; 353d5ac70f0Sopenharmony_ci goto after_sum; 354d5ac70f0Sopenharmony_ci#endif 355d5ac70f0Sopenharmony_ci after_sum: 356d5ac70f0Sopenharmony_ci srcs[srcidx] += src_steps[srcidx]; 357d5ac70f0Sopenharmony_ci ttp++; 358d5ac70f0Sopenharmony_ci } 359d5ac70f0Sopenharmony_ci 360d5ac70f0Sopenharmony_ci /* Normalization */ 361d5ac70f0Sopenharmony_ci goto *norm; 362d5ac70f0Sopenharmony_ci norm_int64_att: 363d5ac70f0Sopenharmony_ci div(sum.as_sint64); 364d5ac70f0Sopenharmony_ci /* fallthru */ 365d5ac70f0Sopenharmony_ci norm_int64_noatt: 366d5ac70f0Sopenharmony_ci if (sum.as_sint64 > (int64_t)0x7fffffff) 367d5ac70f0Sopenharmony_ci sample = 0x7fffffff; /* maximum positive value */ 368d5ac70f0Sopenharmony_ci else if (sum.as_sint64 < -(int64_t)0x80000000) 369d5ac70f0Sopenharmony_ci sample = 0x80000000; /* maximum negative value */ 370d5ac70f0Sopenharmony_ci else 371d5ac70f0Sopenharmony_ci sample = sum.as_sint64; 372d5ac70f0Sopenharmony_ci goto after_norm; 373d5ac70f0Sopenharmony_ci 374d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 375d5ac70f0Sopenharmony_ci norm_float: 376d5ac70f0Sopenharmony_ci sum.as_float = rint(sum.as_float); 377d5ac70f0Sopenharmony_ci if (sum.as_float > (int64_t)0x7fffffff) 378d5ac70f0Sopenharmony_ci sample = 0x7fffffff; /* maximum positive value */ 379d5ac70f0Sopenharmony_ci else if (sum.as_float < -(int64_t)0x80000000) 380d5ac70f0Sopenharmony_ci sample = 0x80000000; /* maximum negative value */ 381d5ac70f0Sopenharmony_ci else 382d5ac70f0Sopenharmony_ci sample = sum.as_float; 383d5ac70f0Sopenharmony_ci goto after_norm; 384d5ac70f0Sopenharmony_ci#endif 385d5ac70f0Sopenharmony_ci after_norm: 386d5ac70f0Sopenharmony_ci 387d5ac70f0Sopenharmony_ci /* Put sample */ 388d5ac70f0Sopenharmony_ci goto *put32; 389d5ac70f0Sopenharmony_ci#define PUT32_END after_put32 390d5ac70f0Sopenharmony_ci#include "plugin_ops.h" 391d5ac70f0Sopenharmony_ci#undef PUT32_END 392d5ac70f0Sopenharmony_ci after_put32: 393d5ac70f0Sopenharmony_ci 394d5ac70f0Sopenharmony_ci dst += dst_step; 395d5ac70f0Sopenharmony_ci } 396d5ac70f0Sopenharmony_ci} 397d5ac70f0Sopenharmony_ci 398d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 399d5ac70f0Sopenharmony_ci 400d5ac70f0Sopenharmony_cistatic void snd_pcm_route_convert(const snd_pcm_channel_area_t *dst_areas, 401d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_offset, 402d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 403d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_offset, 404d5ac70f0Sopenharmony_ci unsigned int src_channels, 405d5ac70f0Sopenharmony_ci unsigned int dst_channels, 406d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames, 407d5ac70f0Sopenharmony_ci snd_pcm_route_params_t *params) 408d5ac70f0Sopenharmony_ci{ 409d5ac70f0Sopenharmony_ci unsigned int dst_channel; 410d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_dst_t *dstp; 411d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_area; 412d5ac70f0Sopenharmony_ci 413d5ac70f0Sopenharmony_ci dstp = params->dsts; 414d5ac70f0Sopenharmony_ci dst_area = dst_areas; 415d5ac70f0Sopenharmony_ci for (dst_channel = 0; dst_channel < dst_channels; ++dst_channel) { 416d5ac70f0Sopenharmony_ci if (dst_channel >= params->ndsts) 417d5ac70f0Sopenharmony_ci snd_pcm_route_convert1_zero(dst_area, dst_offset, 418d5ac70f0Sopenharmony_ci src_areas, src_offset, 419d5ac70f0Sopenharmony_ci src_channels, 420d5ac70f0Sopenharmony_ci frames, dstp, params); 421d5ac70f0Sopenharmony_ci else 422d5ac70f0Sopenharmony_ci dstp->func(dst_area, dst_offset, 423d5ac70f0Sopenharmony_ci src_areas, src_offset, 424d5ac70f0Sopenharmony_ci src_channels, 425d5ac70f0Sopenharmony_ci frames, dstp, params); 426d5ac70f0Sopenharmony_ci dstp++; 427d5ac70f0Sopenharmony_ci dst_area++; 428d5ac70f0Sopenharmony_ci } 429d5ac70f0Sopenharmony_ci} 430d5ac70f0Sopenharmony_ci 431d5ac70f0Sopenharmony_cistatic int snd_pcm_route_close(snd_pcm_t *pcm) 432d5ac70f0Sopenharmony_ci{ 433d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 434d5ac70f0Sopenharmony_ci snd_pcm_route_params_t *params = &route->params; 435d5ac70f0Sopenharmony_ci unsigned int dst_channel; 436d5ac70f0Sopenharmony_ci 437d5ac70f0Sopenharmony_ci if (params->dsts) { 438d5ac70f0Sopenharmony_ci for (dst_channel = 0; dst_channel < params->ndsts; ++dst_channel) { 439d5ac70f0Sopenharmony_ci free(params->dsts[dst_channel].srcs); 440d5ac70f0Sopenharmony_ci } 441d5ac70f0Sopenharmony_ci free(params->dsts); 442d5ac70f0Sopenharmony_ci } 443d5ac70f0Sopenharmony_ci free(route->chmap); 444d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(route->chmap_override); 445d5ac70f0Sopenharmony_ci return snd_pcm_generic_close(pcm); 446d5ac70f0Sopenharmony_ci} 447d5ac70f0Sopenharmony_ci 448d5ac70f0Sopenharmony_cistatic int snd_pcm_route_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) 449d5ac70f0Sopenharmony_ci{ 450d5ac70f0Sopenharmony_ci int err; 451d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 452d5ac70f0Sopenharmony_ci snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; 453d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 454d5ac70f0Sopenharmony_ci &access_mask); 455d5ac70f0Sopenharmony_ci if (err < 0) 456d5ac70f0Sopenharmony_ci return err; 457d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, 458d5ac70f0Sopenharmony_ci &format_mask); 459d5ac70f0Sopenharmony_ci if (err < 0) 460d5ac70f0Sopenharmony_ci return err; 461d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); 462d5ac70f0Sopenharmony_ci if (err < 0) 463d5ac70f0Sopenharmony_ci return err; 464d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); 465d5ac70f0Sopenharmony_ci if (err < 0) 466d5ac70f0Sopenharmony_ci return err; 467d5ac70f0Sopenharmony_ci params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 468d5ac70f0Sopenharmony_ci return 0; 469d5ac70f0Sopenharmony_ci} 470d5ac70f0Sopenharmony_ci 471d5ac70f0Sopenharmony_cistatic int snd_pcm_route_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) 472d5ac70f0Sopenharmony_ci{ 473d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 474d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 475d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_any(sparams); 476d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 477d5ac70f0Sopenharmony_ci &saccess_mask); 478d5ac70f0Sopenharmony_ci if (route->sformat != SND_PCM_FORMAT_UNKNOWN) { 479d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_set_format(sparams, route->sformat); 480d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); 481d5ac70f0Sopenharmony_ci } 482d5ac70f0Sopenharmony_ci if (route->schannels >= 0) { 483d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, 484d5ac70f0Sopenharmony_ci (unsigned int) route->schannels, 0); 485d5ac70f0Sopenharmony_ci } 486d5ac70f0Sopenharmony_ci return 0; 487d5ac70f0Sopenharmony_ci} 488d5ac70f0Sopenharmony_ci 489d5ac70f0Sopenharmony_cistatic int snd_pcm_route_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 490d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 491d5ac70f0Sopenharmony_ci{ 492d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 493d5ac70f0Sopenharmony_ci int err; 494d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_RATE | 495d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS | 496d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 497d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 498d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 499d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 500d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_TICK_TIME); 501d5ac70f0Sopenharmony_ci if (route->sformat == SND_PCM_FORMAT_UNKNOWN) 502d5ac70f0Sopenharmony_ci links |= (SND_PCM_HW_PARBIT_FORMAT | 503d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SUBFORMAT | 504d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SAMPLE_BITS); 505d5ac70f0Sopenharmony_ci if (route->schannels < 0) 506d5ac70f0Sopenharmony_ci links |= SND_PCM_HW_PARBIT_CHANNELS; 507d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(sparams, links, params); 508d5ac70f0Sopenharmony_ci if (err < 0) 509d5ac70f0Sopenharmony_ci return err; 510d5ac70f0Sopenharmony_ci return 0; 511d5ac70f0Sopenharmony_ci} 512d5ac70f0Sopenharmony_ci 513d5ac70f0Sopenharmony_cistatic int snd_pcm_route_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 514d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 515d5ac70f0Sopenharmony_ci{ 516d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 517d5ac70f0Sopenharmony_ci int err; 518d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_RATE | 519d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS | 520d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 521d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 522d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 523d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 524d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_TICK_TIME); 525d5ac70f0Sopenharmony_ci if (route->sformat == SND_PCM_FORMAT_UNKNOWN) 526d5ac70f0Sopenharmony_ci links |= (SND_PCM_HW_PARBIT_FORMAT | 527d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SUBFORMAT | 528d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SAMPLE_BITS); 529d5ac70f0Sopenharmony_ci if (route->schannels < 0) 530d5ac70f0Sopenharmony_ci links |= SND_PCM_HW_PARBIT_CHANNELS; 531d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(params, links, sparams); 532d5ac70f0Sopenharmony_ci if (err < 0) 533d5ac70f0Sopenharmony_ci return err; 534d5ac70f0Sopenharmony_ci return 0; 535d5ac70f0Sopenharmony_ci} 536d5ac70f0Sopenharmony_ci 537d5ac70f0Sopenharmony_cistatic int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 538d5ac70f0Sopenharmony_ci{ 539d5ac70f0Sopenharmony_ci return snd_pcm_hw_refine_slave(pcm, params, 540d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_cprepare, 541d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_cchange, 542d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_sprepare, 543d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_schange, 544d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_refine); 545d5ac70f0Sopenharmony_ci} 546d5ac70f0Sopenharmony_ci 547d5ac70f0Sopenharmony_cistatic int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 548d5ac70f0Sopenharmony_ci{ 549d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 550d5ac70f0Sopenharmony_ci snd_pcm_t *slave = route->plug.gen.slave; 551d5ac70f0Sopenharmony_ci snd_pcm_format_t src_format, dst_format; 552d5ac70f0Sopenharmony_ci int err = snd_pcm_hw_params_slave(pcm, params, 553d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_cchange, 554d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_sprepare, 555d5ac70f0Sopenharmony_ci snd_pcm_route_hw_refine_schange, 556d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_params); 557d5ac70f0Sopenharmony_ci if (err < 0) 558d5ac70f0Sopenharmony_ci return err; 559d5ac70f0Sopenharmony_ci 560d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 561d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_get_format)(params, &src_format); 562d5ac70f0Sopenharmony_ci dst_format = slave->format; 563d5ac70f0Sopenharmony_ci } else { 564d5ac70f0Sopenharmony_ci src_format = slave->format; 565d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format); 566d5ac70f0Sopenharmony_ci } 567d5ac70f0Sopenharmony_ci if (err < 0) 568d5ac70f0Sopenharmony_ci return err; 569d5ac70f0Sopenharmony_ci /* 3 bytes or 20-bit formats? */ 570d5ac70f0Sopenharmony_ci route->params.use_getput = 571d5ac70f0Sopenharmony_ci (snd_pcm_format_physical_width(src_format) + 7) / 8 == 3 || 572d5ac70f0Sopenharmony_ci (snd_pcm_format_physical_width(dst_format) + 7) / 8 == 3 || 573d5ac70f0Sopenharmony_ci snd_pcm_format_width(src_format) == 20 || 574d5ac70f0Sopenharmony_ci snd_pcm_format_width(dst_format) == 20; 575d5ac70f0Sopenharmony_ci route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32); 576d5ac70f0Sopenharmony_ci route->params.put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format); 577d5ac70f0Sopenharmony_ci route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format); 578d5ac70f0Sopenharmony_ci route->params.src_size = snd_pcm_format_width(src_format) / 8; 579d5ac70f0Sopenharmony_ci route->params.dst_sfmt = dst_format; 580d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 581d5ac70f0Sopenharmony_ci route->params.sum_idx = FLOAT; 582d5ac70f0Sopenharmony_ci#else 583d5ac70f0Sopenharmony_ci route->params.sum_idx = UINT64; 584d5ac70f0Sopenharmony_ci#endif 585d5ac70f0Sopenharmony_ci return 0; 586d5ac70f0Sopenharmony_ci} 587d5ac70f0Sopenharmony_ci 588d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 589d5ac70f0Sopenharmony_cisnd_pcm_route_write_areas(snd_pcm_t *pcm, 590d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 591d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 592d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 593d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 594d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 595d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 596d5ac70f0Sopenharmony_ci{ 597d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 598d5ac70f0Sopenharmony_ci snd_pcm_t *slave = route->plug.gen.slave; 599d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 600d5ac70f0Sopenharmony_ci size = *slave_sizep; 601d5ac70f0Sopenharmony_ci snd_pcm_route_convert(slave_areas, slave_offset, 602d5ac70f0Sopenharmony_ci areas, offset, 603d5ac70f0Sopenharmony_ci pcm->channels, 604d5ac70f0Sopenharmony_ci slave->channels, 605d5ac70f0Sopenharmony_ci size, &route->params); 606d5ac70f0Sopenharmony_ci *slave_sizep = size; 607d5ac70f0Sopenharmony_ci return size; 608d5ac70f0Sopenharmony_ci} 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 611d5ac70f0Sopenharmony_cisnd_pcm_route_read_areas(snd_pcm_t *pcm, 612d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 613d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 614d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 615d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 616d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 617d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 618d5ac70f0Sopenharmony_ci{ 619d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 620d5ac70f0Sopenharmony_ci snd_pcm_t *slave = route->plug.gen.slave; 621d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 622d5ac70f0Sopenharmony_ci size = *slave_sizep; 623d5ac70f0Sopenharmony_ci snd_pcm_route_convert(areas, offset, 624d5ac70f0Sopenharmony_ci slave_areas, slave_offset, 625d5ac70f0Sopenharmony_ci slave->channels, 626d5ac70f0Sopenharmony_ci pcm->channels, 627d5ac70f0Sopenharmony_ci size, &route->params); 628d5ac70f0Sopenharmony_ci *slave_sizep = size; 629d5ac70f0Sopenharmony_ci return size; 630d5ac70f0Sopenharmony_ci} 631d5ac70f0Sopenharmony_ci 632d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_t *snd_pcm_route_get_chmap(snd_pcm_t *pcm) 633d5ac70f0Sopenharmony_ci{ 634d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 635d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *map, *slave_map; 636d5ac70f0Sopenharmony_ci unsigned int src, dst, nsrcs; 637d5ac70f0Sopenharmony_ci 638d5ac70f0Sopenharmony_ci if (route->chmap_override) 639d5ac70f0Sopenharmony_ci return _snd_pcm_choose_fixed_chmap(pcm, route->chmap_override); 640d5ac70f0Sopenharmony_ci 641d5ac70f0Sopenharmony_ci slave_map = snd_pcm_generic_get_chmap(pcm); 642d5ac70f0Sopenharmony_ci if (!slave_map) 643d5ac70f0Sopenharmony_ci return NULL; 644d5ac70f0Sopenharmony_ci nsrcs = route->params.nsrcs; 645d5ac70f0Sopenharmony_ci map = calloc(4, nsrcs + 1); 646d5ac70f0Sopenharmony_ci if (!map) { 647d5ac70f0Sopenharmony_ci free(slave_map); 648d5ac70f0Sopenharmony_ci return NULL; 649d5ac70f0Sopenharmony_ci } 650d5ac70f0Sopenharmony_ci map->channels = nsrcs; 651d5ac70f0Sopenharmony_ci for (src = 0; src < nsrcs; src++) 652d5ac70f0Sopenharmony_ci map->pos[src] = SND_CHMAP_NA; 653d5ac70f0Sopenharmony_ci for (dst = 0; dst < route->params.ndsts; dst++) { 654d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst]; 655d5ac70f0Sopenharmony_ci for (src = 0; src < d->nsrcs; src++) { 656d5ac70f0Sopenharmony_ci unsigned int c = d->srcs[src].channel; 657d5ac70f0Sopenharmony_ci if (c < nsrcs && map->pos[c] == SND_CHMAP_NA) 658d5ac70f0Sopenharmony_ci map->pos[c] = slave_map->pos[dst]; 659d5ac70f0Sopenharmony_ci } 660d5ac70f0Sopenharmony_ci } 661d5ac70f0Sopenharmony_ci free(slave_map); 662d5ac70f0Sopenharmony_ci return map; 663d5ac70f0Sopenharmony_ci} 664d5ac70f0Sopenharmony_ci 665d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_query_t **snd_pcm_route_query_chmaps(snd_pcm_t *pcm) 666d5ac70f0Sopenharmony_ci{ 667d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 668d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **maps; 669d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *map; 670d5ac70f0Sopenharmony_ci 671d5ac70f0Sopenharmony_ci if (route->chmap_override) 672d5ac70f0Sopenharmony_ci return _snd_pcm_copy_chmap_query(route->chmap_override); 673d5ac70f0Sopenharmony_ci 674d5ac70f0Sopenharmony_ci map = snd_pcm_route_get_chmap(pcm); 675d5ac70f0Sopenharmony_ci if (!map) 676d5ac70f0Sopenharmony_ci return NULL; 677d5ac70f0Sopenharmony_ci maps = _snd_pcm_make_single_query_chmaps(map); 678d5ac70f0Sopenharmony_ci free(map); 679d5ac70f0Sopenharmony_ci return maps; 680d5ac70f0Sopenharmony_ci} 681d5ac70f0Sopenharmony_ci 682d5ac70f0Sopenharmony_cistatic void snd_pcm_route_dump(snd_pcm_t *pcm, snd_output_t *out) 683d5ac70f0Sopenharmony_ci{ 684d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 685d5ac70f0Sopenharmony_ci unsigned int dst; 686d5ac70f0Sopenharmony_ci if (route->sformat == SND_PCM_FORMAT_UNKNOWN) 687d5ac70f0Sopenharmony_ci snd_output_printf(out, "Route conversion PCM\n"); 688d5ac70f0Sopenharmony_ci else 689d5ac70f0Sopenharmony_ci snd_output_printf(out, "Route conversion PCM (sformat=%s)\n", 690d5ac70f0Sopenharmony_ci snd_pcm_format_name(route->sformat)); 691d5ac70f0Sopenharmony_ci snd_output_puts(out, " Transformation table:\n"); 692d5ac70f0Sopenharmony_ci for (dst = 0; dst < route->params.ndsts; dst++) { 693d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst]; 694d5ac70f0Sopenharmony_ci unsigned int src; 695d5ac70f0Sopenharmony_ci snd_output_printf(out, " %d <- ", dst); 696d5ac70f0Sopenharmony_ci if (d->nsrcs == 0) { 697d5ac70f0Sopenharmony_ci snd_output_printf(out, "none\n"); 698d5ac70f0Sopenharmony_ci continue; 699d5ac70f0Sopenharmony_ci } 700d5ac70f0Sopenharmony_ci src = 0; 701d5ac70f0Sopenharmony_ci while (1) { 702d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_src_t *s = &d->srcs[src]; 703d5ac70f0Sopenharmony_ci if (d->att) 704d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 705d5ac70f0Sopenharmony_ci snd_output_printf(out, "%d*%g", s->channel, s->as_float); 706d5ac70f0Sopenharmony_ci#else 707d5ac70f0Sopenharmony_ci snd_output_printf(out, "%d*%g", s->channel, (double)s->as_int / (double)SND_PCM_PLUGIN_ROUTE_RESOLUTION); 708d5ac70f0Sopenharmony_ci#endif 709d5ac70f0Sopenharmony_ci else 710d5ac70f0Sopenharmony_ci snd_output_printf(out, "%d", s->channel); 711d5ac70f0Sopenharmony_ci src++; 712d5ac70f0Sopenharmony_ci if (src == d->nsrcs) 713d5ac70f0Sopenharmony_ci break; 714d5ac70f0Sopenharmony_ci snd_output_puts(out, " + "); 715d5ac70f0Sopenharmony_ci } 716d5ac70f0Sopenharmony_ci snd_output_putc(out, '\n'); 717d5ac70f0Sopenharmony_ci } 718d5ac70f0Sopenharmony_ci if (pcm->setup) { 719d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 720d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 721d5ac70f0Sopenharmony_ci } 722d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 723d5ac70f0Sopenharmony_ci snd_pcm_dump(route->plug.gen.slave, out); 724d5ac70f0Sopenharmony_ci} 725d5ac70f0Sopenharmony_ci 726d5ac70f0Sopenharmony_ci/* 727d5ac70f0Sopenharmony_ci * Converts a string to an array of channel indices: 728d5ac70f0Sopenharmony_ci * - Given a number, the result is an array with one element, 729d5ac70f0Sopenharmony_ci * containing that number 730d5ac70f0Sopenharmony_ci * - Given a channel name (e g "FL") and a chmap, 731d5ac70f0Sopenharmony_ci * it will look this up in the chmap and return all matches 732d5ac70f0Sopenharmony_ci * - Given a channel name and no chmap, the result is an array with one element, 733d5ac70f0Sopenharmony_ci containing alsa standard channel map. Note that this might be a negative 734d5ac70f0Sopenharmony_ci number in case of "UNKNOWN", "NA" or "MONO". 735d5ac70f0Sopenharmony_ci * Return value is number of matches written. 736d5ac70f0Sopenharmony_ci */ 737d5ac70f0Sopenharmony_cistatic int strtochannel(const char *id, snd_pcm_chmap_t *chmap, 738d5ac70f0Sopenharmony_ci long *channel, int channel_size) 739d5ac70f0Sopenharmony_ci{ 740d5ac70f0Sopenharmony_ci int ch; 741d5ac70f0Sopenharmony_ci if (safe_strtol(id, channel) >= 0) 742d5ac70f0Sopenharmony_ci return 1; 743d5ac70f0Sopenharmony_ci 744d5ac70f0Sopenharmony_ci ch = (int) snd_pcm_chmap_from_string(id); 745d5ac70f0Sopenharmony_ci if (ch == -1) 746d5ac70f0Sopenharmony_ci return -EINVAL; 747d5ac70f0Sopenharmony_ci 748d5ac70f0Sopenharmony_ci if (chmap) { 749d5ac70f0Sopenharmony_ci int i, r = 0; 750d5ac70f0Sopenharmony_ci /* Start with highest channel to simplify implementation of 751d5ac70f0Sopenharmony_ci determine ttable size */ 752d5ac70f0Sopenharmony_ci for (i = chmap->channels - 1; i >= 0; i--) { 753d5ac70f0Sopenharmony_ci if ((int) chmap->pos[i] != ch) 754d5ac70f0Sopenharmony_ci continue; 755d5ac70f0Sopenharmony_ci if (r >= channel_size) 756d5ac70f0Sopenharmony_ci continue; 757d5ac70f0Sopenharmony_ci channel[r++] = i; 758d5ac70f0Sopenharmony_ci } 759d5ac70f0Sopenharmony_ci return r; 760d5ac70f0Sopenharmony_ci } 761d5ac70f0Sopenharmony_ci else { 762d5ac70f0Sopenharmony_ci /* Assume ALSA standard channel mapping */ 763d5ac70f0Sopenharmony_ci *channel = ch - SND_CHMAP_FL; 764d5ac70f0Sopenharmony_ci return 1; 765d5ac70f0Sopenharmony_ci } 766d5ac70f0Sopenharmony_ci} 767d5ac70f0Sopenharmony_ci 768d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 769d5ac70f0Sopenharmony_ci#define MAX_CHMAP_CHANNELS 256 770d5ac70f0Sopenharmony_ci#endif 771d5ac70f0Sopenharmony_ci 772d5ac70f0Sopenharmony_cistatic int determine_chmap(snd_config_t *tt, snd_pcm_chmap_t **tt_chmap) 773d5ac70f0Sopenharmony_ci{ 774d5ac70f0Sopenharmony_ci snd_config_iterator_t i, inext; 775d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *chmap; 776d5ac70f0Sopenharmony_ci 777d5ac70f0Sopenharmony_ci assert(tt && tt_chmap); 778d5ac70f0Sopenharmony_ci chmap = malloc(sizeof(snd_pcm_chmap_t) + 779d5ac70f0Sopenharmony_ci MAX_CHMAP_CHANNELS * sizeof(unsigned int)); 780d5ac70f0Sopenharmony_ci 781d5ac70f0Sopenharmony_ci chmap->channels = 0; 782d5ac70f0Sopenharmony_ci snd_config_for_each(i, inext, tt) { 783d5ac70f0Sopenharmony_ci const char *id; 784d5ac70f0Sopenharmony_ci snd_config_iterator_t j, jnext; 785d5ac70f0Sopenharmony_ci snd_config_t *in = snd_config_iterator_entry(i); 786d5ac70f0Sopenharmony_ci 787d5ac70f0Sopenharmony_ci if (snd_config_get_id(in, &id) < 0) 788d5ac70f0Sopenharmony_ci continue; 789d5ac70f0Sopenharmony_ci if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) 790d5ac70f0Sopenharmony_ci goto err; 791d5ac70f0Sopenharmony_ci snd_config_for_each(j, jnext, in) { 792d5ac70f0Sopenharmony_ci int ch, k, found; 793d5ac70f0Sopenharmony_ci long schannel; 794d5ac70f0Sopenharmony_ci snd_config_t *jnode = snd_config_iterator_entry(j); 795d5ac70f0Sopenharmony_ci if (snd_config_get_id(jnode, &id) < 0) 796d5ac70f0Sopenharmony_ci continue; 797d5ac70f0Sopenharmony_ci if (safe_strtol(id, &schannel) >= 0) 798d5ac70f0Sopenharmony_ci continue; 799d5ac70f0Sopenharmony_ci ch = (int) snd_pcm_chmap_from_string(id); 800d5ac70f0Sopenharmony_ci if (ch == -1) 801d5ac70f0Sopenharmony_ci goto err; 802d5ac70f0Sopenharmony_ci 803d5ac70f0Sopenharmony_ci found = 0; 804d5ac70f0Sopenharmony_ci for (k = 0; k < (int) chmap->channels; k++) 805d5ac70f0Sopenharmony_ci if (ch == (int) chmap->pos[k]) { 806d5ac70f0Sopenharmony_ci found = 1; 807d5ac70f0Sopenharmony_ci break; 808d5ac70f0Sopenharmony_ci } 809d5ac70f0Sopenharmony_ci if (found) 810d5ac70f0Sopenharmony_ci continue; 811d5ac70f0Sopenharmony_ci 812d5ac70f0Sopenharmony_ci if (chmap->channels >= MAX_CHMAP_CHANNELS) { 813d5ac70f0Sopenharmony_ci SNDERR("Too many channels in ttable chmap"); 814d5ac70f0Sopenharmony_ci goto err; 815d5ac70f0Sopenharmony_ci } 816d5ac70f0Sopenharmony_ci chmap->pos[chmap->channels++] = ch; 817d5ac70f0Sopenharmony_ci } 818d5ac70f0Sopenharmony_ci } 819d5ac70f0Sopenharmony_ci 820d5ac70f0Sopenharmony_ci if (chmap->channels == 0) { 821d5ac70f0Sopenharmony_ci free(chmap); 822d5ac70f0Sopenharmony_ci chmap = NULL; 823d5ac70f0Sopenharmony_ci } 824d5ac70f0Sopenharmony_ci *tt_chmap = chmap; 825d5ac70f0Sopenharmony_ci return 0; 826d5ac70f0Sopenharmony_ci 827d5ac70f0Sopenharmony_cierr: 828d5ac70f0Sopenharmony_ci *tt_chmap = NULL; 829d5ac70f0Sopenharmony_ci free(chmap); 830d5ac70f0Sopenharmony_ci return -EINVAL; 831d5ac70f0Sopenharmony_ci} 832d5ac70f0Sopenharmony_ci 833d5ac70f0Sopenharmony_cistatic int find_matching_chmap(snd_pcm_chmap_query_t **chmaps, 834d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *tt_chmap, 835d5ac70f0Sopenharmony_ci snd_pcm_chmap_t **found_chmap, int *schannels) 836d5ac70f0Sopenharmony_ci{ 837d5ac70f0Sopenharmony_ci int i; 838d5ac70f0Sopenharmony_ci 839d5ac70f0Sopenharmony_ci *found_chmap = NULL; 840d5ac70f0Sopenharmony_ci 841d5ac70f0Sopenharmony_ci if (chmaps == NULL) 842d5ac70f0Sopenharmony_ci return 0; /* chmap API not supported for this slave */ 843d5ac70f0Sopenharmony_ci 844d5ac70f0Sopenharmony_ci for (i = 0; chmaps[i]; i++) { 845d5ac70f0Sopenharmony_ci unsigned int j, k; 846d5ac70f0Sopenharmony_ci int match = 1; 847d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *c = &chmaps[i]->map; 848d5ac70f0Sopenharmony_ci if (*schannels >= 0 && (int) c->channels != *schannels) 849d5ac70f0Sopenharmony_ci continue; 850d5ac70f0Sopenharmony_ci 851d5ac70f0Sopenharmony_ci for (j = 0; j < tt_chmap->channels; j++) { 852d5ac70f0Sopenharmony_ci int found = 0; 853d5ac70f0Sopenharmony_ci unsigned int ch = tt_chmap->pos[j]; 854d5ac70f0Sopenharmony_ci for (k = 0; k < c->channels; k++) 855d5ac70f0Sopenharmony_ci if (c->pos[k] == ch) { 856d5ac70f0Sopenharmony_ci found = 1; 857d5ac70f0Sopenharmony_ci break; 858d5ac70f0Sopenharmony_ci } 859d5ac70f0Sopenharmony_ci if (!found) { 860d5ac70f0Sopenharmony_ci match = 0; 861d5ac70f0Sopenharmony_ci break; 862d5ac70f0Sopenharmony_ci } 863d5ac70f0Sopenharmony_ci } 864d5ac70f0Sopenharmony_ci 865d5ac70f0Sopenharmony_ci if (match) { 866d5ac70f0Sopenharmony_ci int size = sizeof(snd_pcm_chmap_t) + c->channels * sizeof(unsigned int); 867d5ac70f0Sopenharmony_ci *found_chmap = malloc(size); 868d5ac70f0Sopenharmony_ci if (!*found_chmap) { 869d5ac70f0Sopenharmony_ci return -ENOMEM; 870d5ac70f0Sopenharmony_ci } 871d5ac70f0Sopenharmony_ci memcpy(*found_chmap, c, size); 872d5ac70f0Sopenharmony_ci *schannels = c->channels; 873d5ac70f0Sopenharmony_ci break; 874d5ac70f0Sopenharmony_ci } 875d5ac70f0Sopenharmony_ci } 876d5ac70f0Sopenharmony_ci 877d5ac70f0Sopenharmony_ci if (*found_chmap == NULL) { 878d5ac70f0Sopenharmony_ci SNDERR("Found no matching channel map"); 879d5ac70f0Sopenharmony_ci return -EINVAL; 880d5ac70f0Sopenharmony_ci } 881d5ac70f0Sopenharmony_ci return 0; 882d5ac70f0Sopenharmony_ci} 883d5ac70f0Sopenharmony_ci 884d5ac70f0Sopenharmony_cistatic int route_chmap_init(snd_pcm_t *pcm) 885d5ac70f0Sopenharmony_ci{ 886d5ac70f0Sopenharmony_ci int set_map = 0; 887d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *current; 888d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = pcm->private_data; 889d5ac70f0Sopenharmony_ci if (!route->chmap) 890d5ac70f0Sopenharmony_ci return 0; 891d5ac70f0Sopenharmony_ci if (__snd_pcm_state(pcm) != SND_PCM_STATE_PREPARED) 892d5ac70f0Sopenharmony_ci return 0; 893d5ac70f0Sopenharmony_ci 894d5ac70f0Sopenharmony_ci /* Check if we really need to set the chmap or not. 895d5ac70f0Sopenharmony_ci This is important in case set_chmap is not implemented. */ 896d5ac70f0Sopenharmony_ci current = snd_pcm_get_chmap(route->plug.gen.slave); 897d5ac70f0Sopenharmony_ci if (!current) 898d5ac70f0Sopenharmony_ci return -ENOSYS; 899d5ac70f0Sopenharmony_ci if (current->channels != route->chmap->channels) 900d5ac70f0Sopenharmony_ci set_map = 1; 901d5ac70f0Sopenharmony_ci else 902d5ac70f0Sopenharmony_ci set_map = memcmp(current->pos, route->chmap->pos, 903d5ac70f0Sopenharmony_ci current->channels); 904d5ac70f0Sopenharmony_ci free(current); 905d5ac70f0Sopenharmony_ci if (!set_map) 906d5ac70f0Sopenharmony_ci return 0; 907d5ac70f0Sopenharmony_ci 908d5ac70f0Sopenharmony_ci return snd_pcm_set_chmap(route->plug.gen.slave, route->chmap); 909d5ac70f0Sopenharmony_ci} 910d5ac70f0Sopenharmony_ci 911d5ac70f0Sopenharmony_ci 912d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_route_ops = { 913d5ac70f0Sopenharmony_ci .close = snd_pcm_route_close, 914d5ac70f0Sopenharmony_ci .info = snd_pcm_generic_info, 915d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_route_hw_refine, 916d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_route_hw_params, 917d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_generic_hw_free, 918d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_generic_sw_params, 919d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_generic_channel_info, 920d5ac70f0Sopenharmony_ci .dump = snd_pcm_route_dump, 921d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_generic_nonblock, 922d5ac70f0Sopenharmony_ci .async = snd_pcm_generic_async, 923d5ac70f0Sopenharmony_ci .mmap = snd_pcm_generic_mmap, 924d5ac70f0Sopenharmony_ci .munmap = snd_pcm_generic_munmap, 925d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_route_query_chmaps, 926d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_route_get_chmap, 927d5ac70f0Sopenharmony_ci .set_chmap = NULL, /* NYI */ 928d5ac70f0Sopenharmony_ci}; 929d5ac70f0Sopenharmony_ci 930d5ac70f0Sopenharmony_cistatic int route_load_ttable(snd_pcm_route_params_t *params, snd_pcm_stream_t stream, 931d5ac70f0Sopenharmony_ci unsigned int tt_ssize, 932d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_entry_t *ttable, 933d5ac70f0Sopenharmony_ci unsigned int tt_cused, unsigned int tt_sused) 934d5ac70f0Sopenharmony_ci{ 935d5ac70f0Sopenharmony_ci unsigned int src_channel, dst_channel; 936d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_dst_t *dptr; 937d5ac70f0Sopenharmony_ci unsigned int sused, dused, smul, dmul; 938d5ac70f0Sopenharmony_ci if (stream == SND_PCM_STREAM_PLAYBACK) { 939d5ac70f0Sopenharmony_ci sused = tt_cused; 940d5ac70f0Sopenharmony_ci dused = tt_sused; 941d5ac70f0Sopenharmony_ci smul = tt_ssize; 942d5ac70f0Sopenharmony_ci dmul = 1; 943d5ac70f0Sopenharmony_ci } else { 944d5ac70f0Sopenharmony_ci sused = tt_sused; 945d5ac70f0Sopenharmony_ci dused = tt_cused; 946d5ac70f0Sopenharmony_ci smul = 1; 947d5ac70f0Sopenharmony_ci dmul = tt_ssize; 948d5ac70f0Sopenharmony_ci } 949d5ac70f0Sopenharmony_ci params->ndsts = dused; 950d5ac70f0Sopenharmony_ci params->nsrcs = sused; 951d5ac70f0Sopenharmony_ci dptr = calloc(dused, sizeof(*params->dsts)); 952d5ac70f0Sopenharmony_ci if (!dptr) 953d5ac70f0Sopenharmony_ci return -ENOMEM; 954d5ac70f0Sopenharmony_ci params->dsts = dptr; 955d5ac70f0Sopenharmony_ci for (dst_channel = 0; dst_channel < dused; ++dst_channel) { 956d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_entry_t t = 0; 957d5ac70f0Sopenharmony_ci int att = 0; 958d5ac70f0Sopenharmony_ci int nsrcs = 0; 959d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_src_t srcs[sused]; 960d5ac70f0Sopenharmony_ci for (src_channel = 0; src_channel < sused; ++src_channel) { 961d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_entry_t v; 962d5ac70f0Sopenharmony_ci v = ttable[src_channel * smul + dst_channel * dmul]; 963d5ac70f0Sopenharmony_ci if (v != 0) { 964d5ac70f0Sopenharmony_ci srcs[nsrcs].channel = src_channel; 965d5ac70f0Sopenharmony_ci#if SND_PCM_PLUGIN_ROUTE_FLOAT 966d5ac70f0Sopenharmony_ci /* Also in user space for non attenuated */ 967d5ac70f0Sopenharmony_ci srcs[nsrcs].as_int = (v == SND_PCM_PLUGIN_ROUTE_FULL ? SND_PCM_PLUGIN_ROUTE_RESOLUTION : 0); 968d5ac70f0Sopenharmony_ci srcs[nsrcs].as_float = v; 969d5ac70f0Sopenharmony_ci#else 970d5ac70f0Sopenharmony_ci assert(v >= 0 && v <= SND_PCM_PLUGIN_ROUTE_FULL); 971d5ac70f0Sopenharmony_ci srcs[nsrcs].as_int = v; 972d5ac70f0Sopenharmony_ci#endif 973d5ac70f0Sopenharmony_ci if (v != SND_PCM_PLUGIN_ROUTE_FULL) 974d5ac70f0Sopenharmony_ci att = 1; 975d5ac70f0Sopenharmony_ci t += v; 976d5ac70f0Sopenharmony_ci nsrcs++; 977d5ac70f0Sopenharmony_ci } 978d5ac70f0Sopenharmony_ci } 979d5ac70f0Sopenharmony_ci#if 0 980d5ac70f0Sopenharmony_ci assert(t <= SND_PCM_PLUGIN_ROUTE_FULL); 981d5ac70f0Sopenharmony_ci#endif 982d5ac70f0Sopenharmony_ci dptr->att = att; 983d5ac70f0Sopenharmony_ci dptr->nsrcs = nsrcs; 984d5ac70f0Sopenharmony_ci if (nsrcs == 0) 985d5ac70f0Sopenharmony_ci dptr->func = snd_pcm_route_convert1_zero; 986d5ac70f0Sopenharmony_ci else 987d5ac70f0Sopenharmony_ci dptr->func = snd_pcm_route_convert1_many; 988d5ac70f0Sopenharmony_ci if (nsrcs > 0) { 989d5ac70f0Sopenharmony_ci dptr->srcs = calloc((unsigned int) nsrcs, sizeof(*srcs)); 990d5ac70f0Sopenharmony_ci if (!dptr->srcs) 991d5ac70f0Sopenharmony_ci return -ENOMEM; 992d5ac70f0Sopenharmony_ci memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs); 993d5ac70f0Sopenharmony_ci } else 994d5ac70f0Sopenharmony_ci dptr->srcs = 0; 995d5ac70f0Sopenharmony_ci dptr++; 996d5ac70f0Sopenharmony_ci } 997d5ac70f0Sopenharmony_ci return 0; 998d5ac70f0Sopenharmony_ci} 999d5ac70f0Sopenharmony_ci 1000d5ac70f0Sopenharmony_ci/** 1001d5ac70f0Sopenharmony_ci * \brief Creates a new Route & Volume PCM 1002d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1003d5ac70f0Sopenharmony_ci * \param name Name of PCM 1004d5ac70f0Sopenharmony_ci * \param sformat Slave format 1005d5ac70f0Sopenharmony_ci * \param schannels Slave channels 1006d5ac70f0Sopenharmony_ci * \param ttable Attenuation table 1007d5ac70f0Sopenharmony_ci * \param tt_ssize Attenuation table - slave size 1008d5ac70f0Sopenharmony_ci * \param tt_cused Attenuation table - client used count 1009d5ac70f0Sopenharmony_ci * \param tt_sused Attenuation table - slave used count 1010d5ac70f0Sopenharmony_ci * \param slave Slave PCM handle 1011d5ac70f0Sopenharmony_ci * \param close_slave When set, the slave PCM handle is closed with copy PCM 1012d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1013d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1014d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1015d5ac70f0Sopenharmony_ci * changed in future. 1016d5ac70f0Sopenharmony_ci */ 1017d5ac70f0Sopenharmony_ciint snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, 1018d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat, int schannels, 1019d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_entry_t *ttable, 1020d5ac70f0Sopenharmony_ci unsigned int tt_ssize, 1021d5ac70f0Sopenharmony_ci unsigned int tt_cused, unsigned int tt_sused, 1022d5ac70f0Sopenharmony_ci snd_pcm_t *slave, int close_slave) 1023d5ac70f0Sopenharmony_ci{ 1024d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 1025d5ac70f0Sopenharmony_ci snd_pcm_route_t *route; 1026d5ac70f0Sopenharmony_ci int err; 1027d5ac70f0Sopenharmony_ci assert(pcmp && slave && ttable); 1028d5ac70f0Sopenharmony_ci if (sformat != SND_PCM_FORMAT_UNKNOWN && 1029d5ac70f0Sopenharmony_ci snd_pcm_format_linear(sformat) != 1) 1030d5ac70f0Sopenharmony_ci return -EINVAL; 1031d5ac70f0Sopenharmony_ci route = calloc(1, sizeof(snd_pcm_route_t)); 1032d5ac70f0Sopenharmony_ci if (!route) { 1033d5ac70f0Sopenharmony_ci return -ENOMEM; 1034d5ac70f0Sopenharmony_ci } 1035d5ac70f0Sopenharmony_ci snd_pcm_plugin_init(&route->plug); 1036d5ac70f0Sopenharmony_ci route->sformat = sformat; 1037d5ac70f0Sopenharmony_ci route->schannels = schannels; 1038d5ac70f0Sopenharmony_ci route->plug.read = snd_pcm_route_read_areas; 1039d5ac70f0Sopenharmony_ci route->plug.write = snd_pcm_route_write_areas; 1040d5ac70f0Sopenharmony_ci route->plug.undo_read = snd_pcm_plugin_undo_read_generic; 1041d5ac70f0Sopenharmony_ci route->plug.undo_write = snd_pcm_plugin_undo_write_generic; 1042d5ac70f0Sopenharmony_ci route->plug.gen.slave = slave; 1043d5ac70f0Sopenharmony_ci route->plug.gen.close_slave = close_slave; 1044d5ac70f0Sopenharmony_ci route->plug.init = route_chmap_init; 1045d5ac70f0Sopenharmony_ci 1046d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_ROUTE, name, slave->stream, slave->mode); 1047d5ac70f0Sopenharmony_ci if (err < 0) { 1048d5ac70f0Sopenharmony_ci free(route); 1049d5ac70f0Sopenharmony_ci return err; 1050d5ac70f0Sopenharmony_ci } 1051d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_route_ops; 1052d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_plugin_fast_ops; 1053d5ac70f0Sopenharmony_ci pcm->private_data = route; 1054d5ac70f0Sopenharmony_ci pcm->poll_fd = slave->poll_fd; 1055d5ac70f0Sopenharmony_ci pcm->poll_events = slave->poll_events; 1056d5ac70f0Sopenharmony_ci pcm->tstamp_type = slave->tstamp_type; 1057d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0); 1058d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0); 1059d5ac70f0Sopenharmony_ci err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused); 1060d5ac70f0Sopenharmony_ci if (err < 0) { 1061d5ac70f0Sopenharmony_ci snd_pcm_close(pcm); 1062d5ac70f0Sopenharmony_ci return err; 1063d5ac70f0Sopenharmony_ci } 1064d5ac70f0Sopenharmony_ci *pcmp = pcm; 1065d5ac70f0Sopenharmony_ci 1066d5ac70f0Sopenharmony_ci return 0; 1067d5ac70f0Sopenharmony_ci} 1068d5ac70f0Sopenharmony_ci 1069d5ac70f0Sopenharmony_cistatic int _snd_pcm_route_determine_ttable(snd_config_t *tt, 1070d5ac70f0Sopenharmony_ci unsigned int *tt_csize, 1071d5ac70f0Sopenharmony_ci unsigned int *tt_ssize, 1072d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *chmap) 1073d5ac70f0Sopenharmony_ci{ 1074d5ac70f0Sopenharmony_ci snd_config_iterator_t i, inext; 1075d5ac70f0Sopenharmony_ci long csize = 0, ssize = 0; 1076d5ac70f0Sopenharmony_ci int err; 1077d5ac70f0Sopenharmony_ci 1078d5ac70f0Sopenharmony_ci assert(tt && tt_csize && tt_ssize); 1079d5ac70f0Sopenharmony_ci snd_config_for_each(i, inext, tt) { 1080d5ac70f0Sopenharmony_ci snd_config_t *in = snd_config_iterator_entry(i); 1081d5ac70f0Sopenharmony_ci snd_config_iterator_t j, jnext; 1082d5ac70f0Sopenharmony_ci long cchannel; 1083d5ac70f0Sopenharmony_ci const char *id; 1084d5ac70f0Sopenharmony_ci if (snd_config_get_id(in, &id) < 0) 1085d5ac70f0Sopenharmony_ci continue; 1086d5ac70f0Sopenharmony_ci err = safe_strtol(id, &cchannel); 1087d5ac70f0Sopenharmony_ci if (err < 0) { 1088d5ac70f0Sopenharmony_ci SNDERR("Invalid client channel: %s", id); 1089d5ac70f0Sopenharmony_ci return -EINVAL; 1090d5ac70f0Sopenharmony_ci } 1091d5ac70f0Sopenharmony_ci if (cchannel + 1 > csize) 1092d5ac70f0Sopenharmony_ci csize = cchannel + 1; 1093d5ac70f0Sopenharmony_ci if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) 1094d5ac70f0Sopenharmony_ci return -EINVAL; 1095d5ac70f0Sopenharmony_ci snd_config_for_each(j, jnext, in) { 1096d5ac70f0Sopenharmony_ci snd_config_t *jnode = snd_config_iterator_entry(j); 1097d5ac70f0Sopenharmony_ci long schannel; 1098d5ac70f0Sopenharmony_ci const char *id; 1099d5ac70f0Sopenharmony_ci if (snd_config_get_id(jnode, &id) < 0) 1100d5ac70f0Sopenharmony_ci continue; 1101d5ac70f0Sopenharmony_ci err = strtochannel(id, chmap, &schannel, 1); 1102d5ac70f0Sopenharmony_ci if (err < 0) { 1103d5ac70f0Sopenharmony_ci SNDERR("Invalid slave channel: %s", id); 1104d5ac70f0Sopenharmony_ci return -EINVAL; 1105d5ac70f0Sopenharmony_ci } 1106d5ac70f0Sopenharmony_ci if (schannel + 1 > ssize) 1107d5ac70f0Sopenharmony_ci ssize = schannel + 1; 1108d5ac70f0Sopenharmony_ci } 1109d5ac70f0Sopenharmony_ci } 1110d5ac70f0Sopenharmony_ci if (csize == 0 || ssize == 0) { 1111d5ac70f0Sopenharmony_ci SNDERR("Invalid null ttable configuration"); 1112d5ac70f0Sopenharmony_ci return -EINVAL; 1113d5ac70f0Sopenharmony_ci } 1114d5ac70f0Sopenharmony_ci *tt_csize = csize; 1115d5ac70f0Sopenharmony_ci *tt_ssize = ssize; 1116d5ac70f0Sopenharmony_ci return 0; 1117d5ac70f0Sopenharmony_ci} 1118d5ac70f0Sopenharmony_ci 1119d5ac70f0Sopenharmony_ci/** 1120d5ac70f0Sopenharmony_ci * \brief Determine route matrix sizes 1121d5ac70f0Sopenharmony_ci * \param tt Configuration root describing route matrix 1122d5ac70f0Sopenharmony_ci * \param tt_csize Returned client size in elements 1123d5ac70f0Sopenharmony_ci * \param tt_ssize Returned slave size in elements 1124d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1125d5ac70f0Sopenharmony_ci */ 1126d5ac70f0Sopenharmony_ciint snd_pcm_route_determine_ttable(snd_config_t *tt, 1127d5ac70f0Sopenharmony_ci unsigned int *tt_csize, 1128d5ac70f0Sopenharmony_ci unsigned int *tt_ssize) 1129d5ac70f0Sopenharmony_ci{ 1130d5ac70f0Sopenharmony_ci return _snd_pcm_route_determine_ttable(tt, tt_csize, tt_ssize, NULL); 1131d5ac70f0Sopenharmony_ci} 1132d5ac70f0Sopenharmony_ci 1133d5ac70f0Sopenharmony_ci/** 1134d5ac70f0Sopenharmony_ci * \brief Load route matrix 1135d5ac70f0Sopenharmony_ci * \param tt Configuration root describing route matrix 1136d5ac70f0Sopenharmony_ci * \param ttable Returned route matrix 1137d5ac70f0Sopenharmony_ci * \param tt_csize Client size in elements 1138d5ac70f0Sopenharmony_ci * \param tt_ssize Slave size in elements 1139d5ac70f0Sopenharmony_ci * \param tt_cused Used client elements 1140d5ac70f0Sopenharmony_ci * \param tt_sused Used slave elements 1141d5ac70f0Sopenharmony_ci * \param schannels Slave channels 1142d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1143d5ac70f0Sopenharmony_ci */ 1144d5ac70f0Sopenharmony_cistatic int _snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, 1145d5ac70f0Sopenharmony_ci unsigned int tt_csize, unsigned int tt_ssize, 1146d5ac70f0Sopenharmony_ci unsigned int *tt_cused, unsigned int *tt_sused, 1147d5ac70f0Sopenharmony_ci int schannels, snd_pcm_chmap_t *chmap) 1148d5ac70f0Sopenharmony_ci{ 1149d5ac70f0Sopenharmony_ci int cused = -1; 1150d5ac70f0Sopenharmony_ci int sused = -1; 1151d5ac70f0Sopenharmony_ci snd_config_iterator_t i, inext; 1152d5ac70f0Sopenharmony_ci unsigned int k; 1153d5ac70f0Sopenharmony_ci int err; 1154d5ac70f0Sopenharmony_ci 1155d5ac70f0Sopenharmony_ci long *scha = alloca(tt_ssize * sizeof(long)); 1156d5ac70f0Sopenharmony_ci if (scha == NULL) 1157d5ac70f0Sopenharmony_ci return -ENOMEM; 1158d5ac70f0Sopenharmony_ci 1159d5ac70f0Sopenharmony_ci for (k = 0; k < tt_csize * tt_ssize; ++k) 1160d5ac70f0Sopenharmony_ci ttable[k] = 0.0; 1161d5ac70f0Sopenharmony_ci snd_config_for_each(i, inext, tt) { 1162d5ac70f0Sopenharmony_ci snd_config_t *in = snd_config_iterator_entry(i); 1163d5ac70f0Sopenharmony_ci snd_config_iterator_t j, jnext; 1164d5ac70f0Sopenharmony_ci long cchannel; 1165d5ac70f0Sopenharmony_ci const char *id; 1166d5ac70f0Sopenharmony_ci if (snd_config_get_id(in, &id) < 0) 1167d5ac70f0Sopenharmony_ci continue; 1168d5ac70f0Sopenharmony_ci err = safe_strtol(id, &cchannel); 1169d5ac70f0Sopenharmony_ci if (err < 0 || 1170d5ac70f0Sopenharmony_ci cchannel < 0 || (unsigned int) cchannel > tt_csize) { 1171d5ac70f0Sopenharmony_ci SNDERR("Invalid client channel: %s", id); 1172d5ac70f0Sopenharmony_ci return -EINVAL; 1173d5ac70f0Sopenharmony_ci } 1174d5ac70f0Sopenharmony_ci if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) 1175d5ac70f0Sopenharmony_ci return -EINVAL; 1176d5ac70f0Sopenharmony_ci snd_config_for_each(j, jnext, in) { 1177d5ac70f0Sopenharmony_ci snd_config_t *jnode = snd_config_iterator_entry(j); 1178d5ac70f0Sopenharmony_ci double value; 1179d5ac70f0Sopenharmony_ci int ss; 1180d5ac70f0Sopenharmony_ci const char *id; 1181d5ac70f0Sopenharmony_ci if (snd_config_get_id(jnode, &id) < 0) 1182d5ac70f0Sopenharmony_ci continue; 1183d5ac70f0Sopenharmony_ci 1184d5ac70f0Sopenharmony_ci ss = strtochannel(id, chmap, scha, tt_ssize); 1185d5ac70f0Sopenharmony_ci if (ss < 0) { 1186d5ac70f0Sopenharmony_ci SNDERR("Invalid slave channel: %s", id); 1187d5ac70f0Sopenharmony_ci return -EINVAL; 1188d5ac70f0Sopenharmony_ci } 1189d5ac70f0Sopenharmony_ci 1190d5ac70f0Sopenharmony_ci err = snd_config_get_ireal(jnode, &value); 1191d5ac70f0Sopenharmony_ci if (err < 0) { 1192d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1193d5ac70f0Sopenharmony_ci return -EINVAL; 1194d5ac70f0Sopenharmony_ci } 1195d5ac70f0Sopenharmony_ci 1196d5ac70f0Sopenharmony_ci for (k = 0; (int) k < ss; k++) { 1197d5ac70f0Sopenharmony_ci long schannel = scha[k]; 1198d5ac70f0Sopenharmony_ci if (schannel < 0 || (unsigned int) schannel > tt_ssize || 1199d5ac70f0Sopenharmony_ci (schannels > 0 && schannel >= schannels)) { 1200d5ac70f0Sopenharmony_ci SNDERR("Invalid slave channel: %s", id); 1201d5ac70f0Sopenharmony_ci return -EINVAL; 1202d5ac70f0Sopenharmony_ci } 1203d5ac70f0Sopenharmony_ci ttable[cchannel * tt_ssize + schannel] = value; 1204d5ac70f0Sopenharmony_ci if (schannel > sused) 1205d5ac70f0Sopenharmony_ci sused = schannel; 1206d5ac70f0Sopenharmony_ci } 1207d5ac70f0Sopenharmony_ci } 1208d5ac70f0Sopenharmony_ci if (cchannel > cused) 1209d5ac70f0Sopenharmony_ci cused = cchannel; 1210d5ac70f0Sopenharmony_ci } 1211d5ac70f0Sopenharmony_ci *tt_sused = sused + 1; 1212d5ac70f0Sopenharmony_ci *tt_cused = cused + 1; 1213d5ac70f0Sopenharmony_ci return 0; 1214d5ac70f0Sopenharmony_ci} 1215d5ac70f0Sopenharmony_ci 1216d5ac70f0Sopenharmony_ci/** 1217d5ac70f0Sopenharmony_ci * \brief Load route matrix 1218d5ac70f0Sopenharmony_ci * \param tt Configuration root describing route matrix 1219d5ac70f0Sopenharmony_ci * \param ttable Returned route matrix 1220d5ac70f0Sopenharmony_ci * \param tt_csize Client size in elements 1221d5ac70f0Sopenharmony_ci * \param tt_ssize Slave size in elements 1222d5ac70f0Sopenharmony_ci * \param tt_cused Used client elements 1223d5ac70f0Sopenharmony_ci * \param tt_sused Used slave elements 1224d5ac70f0Sopenharmony_ci * \param schannels Slave channels 1225d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1226d5ac70f0Sopenharmony_ci */ 1227d5ac70f0Sopenharmony_ciint snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, 1228d5ac70f0Sopenharmony_ci unsigned int tt_csize, unsigned int tt_ssize, 1229d5ac70f0Sopenharmony_ci unsigned int *tt_cused, unsigned int *tt_sused, 1230d5ac70f0Sopenharmony_ci int schannels) 1231d5ac70f0Sopenharmony_ci{ 1232d5ac70f0Sopenharmony_ci return _snd_pcm_route_load_ttable(tt, ttable, tt_csize, tt_ssize, 1233d5ac70f0Sopenharmony_ci tt_cused, tt_sused, schannels, NULL); 1234d5ac70f0Sopenharmony_ci} 1235d5ac70f0Sopenharmony_ci 1236d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 1237d5ac70f0Sopenharmony_ci 1238d5ac70f0Sopenharmony_ci\section pcm_plugins_route Plugin: Route & Volume 1239d5ac70f0Sopenharmony_ci 1240d5ac70f0Sopenharmony_ciThis plugin converts channels and applies volume during the conversion. 1241d5ac70f0Sopenharmony_ciThe format and rate must match for both of them. 1242d5ac70f0Sopenharmony_ci 1243d5ac70f0Sopenharmony_ciSCHANNEL can be a channel name instead of a number (e g FL, LFE). 1244d5ac70f0Sopenharmony_ciIf so, a matching channel map will be selected for the slave. 1245d5ac70f0Sopenharmony_ci 1246d5ac70f0Sopenharmony_ci\code 1247d5ac70f0Sopenharmony_cipcm.name { 1248d5ac70f0Sopenharmony_ci type route # Route & Volume conversion PCM 1249d5ac70f0Sopenharmony_ci slave STR # Slave name 1250d5ac70f0Sopenharmony_ci # or 1251d5ac70f0Sopenharmony_ci slave { # Slave definition 1252d5ac70f0Sopenharmony_ci pcm STR # Slave PCM name 1253d5ac70f0Sopenharmony_ci # or 1254d5ac70f0Sopenharmony_ci pcm { } # Slave PCM definition 1255d5ac70f0Sopenharmony_ci [format STR] # Slave format 1256d5ac70f0Sopenharmony_ci [channels INT] # Slave channels 1257d5ac70f0Sopenharmony_ci } 1258d5ac70f0Sopenharmony_ci ttable { # Transfer table (bi-dimensional compound of cchannels * schannels numbers) 1259d5ac70f0Sopenharmony_ci CCHANNEL { 1260d5ac70f0Sopenharmony_ci SCHANNEL REAL # route value (0.0 - 1.0) 1261d5ac70f0Sopenharmony_ci } 1262d5ac70f0Sopenharmony_ci } 1263d5ac70f0Sopenharmony_ci [chmap MAP] # Override channel maps; MAP is a string array 1264d5ac70f0Sopenharmony_ci} 1265d5ac70f0Sopenharmony_ci\endcode 1266d5ac70f0Sopenharmony_ci 1267d5ac70f0Sopenharmony_ci\subsection pcm_plugins_route_funcref Function reference 1268d5ac70f0Sopenharmony_ci 1269d5ac70f0Sopenharmony_ci<UL> 1270d5ac70f0Sopenharmony_ci <LI>snd_pcm_route_open() 1271d5ac70f0Sopenharmony_ci <LI>_snd_pcm_route_open() 1272d5ac70f0Sopenharmony_ci</UL> 1273d5ac70f0Sopenharmony_ci 1274d5ac70f0Sopenharmony_ci*/ 1275d5ac70f0Sopenharmony_ci 1276d5ac70f0Sopenharmony_ci/** 1277d5ac70f0Sopenharmony_ci * \brief Creates a new Route & Volume PCM 1278d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1279d5ac70f0Sopenharmony_ci * \param name Name of PCM 1280d5ac70f0Sopenharmony_ci * \param root Root configuration node 1281d5ac70f0Sopenharmony_ci * \param conf Configuration node with Route & Volume PCM description 1282d5ac70f0Sopenharmony_ci * \param stream Stream type 1283d5ac70f0Sopenharmony_ci * \param mode Stream mode 1284d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1285d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1286d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1287d5ac70f0Sopenharmony_ci * changed in future. 1288d5ac70f0Sopenharmony_ci */ 1289d5ac70f0Sopenharmony_ciint _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, 1290d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 1291d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1292d5ac70f0Sopenharmony_ci{ 1293d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1294d5ac70f0Sopenharmony_ci int err; 1295d5ac70f0Sopenharmony_ci snd_pcm_t *spcm; 1296d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL, *sconf; 1297d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *tt_chmap = NULL, *chmap = NULL; 1298d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; 1299d5ac70f0Sopenharmony_ci int schannels = -1; 1300d5ac70f0Sopenharmony_ci snd_config_t *tt = NULL; 1301d5ac70f0Sopenharmony_ci snd_pcm_route_ttable_entry_t *ttable = NULL; 1302d5ac70f0Sopenharmony_ci unsigned int csize, ssize; 1303d5ac70f0Sopenharmony_ci unsigned int cused, sused; 1304d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **chmaps = NULL; 1305d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 1306d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1307d5ac70f0Sopenharmony_ci const char *id; 1308d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1309d5ac70f0Sopenharmony_ci continue; 1310d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 1311d5ac70f0Sopenharmony_ci continue; 1312d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 1313d5ac70f0Sopenharmony_ci slave = n; 1314d5ac70f0Sopenharmony_ci continue; 1315d5ac70f0Sopenharmony_ci } 1316d5ac70f0Sopenharmony_ci if (strcmp(id, "ttable") == 0) { 1317d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 1318d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1319d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1320d5ac70f0Sopenharmony_ci return -EINVAL; 1321d5ac70f0Sopenharmony_ci } 1322d5ac70f0Sopenharmony_ci tt = n; 1323d5ac70f0Sopenharmony_ci continue; 1324d5ac70f0Sopenharmony_ci } 1325d5ac70f0Sopenharmony_ci if (strcmp(id, "chmap") == 0) { 1326d5ac70f0Sopenharmony_ci chmaps = _snd_pcm_parse_config_chmaps(n); 1327d5ac70f0Sopenharmony_ci if (!chmaps) { 1328d5ac70f0Sopenharmony_ci SNDERR("Invalid channel map for %s", id); 1329d5ac70f0Sopenharmony_ci return -EINVAL; 1330d5ac70f0Sopenharmony_ci } 1331d5ac70f0Sopenharmony_ci continue; 1332d5ac70f0Sopenharmony_ci } 1333d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 1334d5ac70f0Sopenharmony_ci return -EINVAL; 1335d5ac70f0Sopenharmony_ci } 1336d5ac70f0Sopenharmony_ci if (!slave) { 1337d5ac70f0Sopenharmony_ci SNDERR("slave is not defined"); 1338d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1339d5ac70f0Sopenharmony_ci return -EINVAL; 1340d5ac70f0Sopenharmony_ci } 1341d5ac70f0Sopenharmony_ci if (!tt) { 1342d5ac70f0Sopenharmony_ci SNDERR("ttable is not defined"); 1343d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1344d5ac70f0Sopenharmony_ci return -EINVAL; 1345d5ac70f0Sopenharmony_ci } 1346d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave, &sconf, 2, 1347d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, 0, &sformat, 1348d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, 0, &schannels); 1349d5ac70f0Sopenharmony_ci if (err < 0) { 1350d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1351d5ac70f0Sopenharmony_ci return err; 1352d5ac70f0Sopenharmony_ci } 1353d5ac70f0Sopenharmony_ci if (sformat != SND_PCM_FORMAT_UNKNOWN && 1354d5ac70f0Sopenharmony_ci snd_pcm_format_linear(sformat) != 1) { 1355d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1356d5ac70f0Sopenharmony_ci SNDERR("slave format is not linear"); 1357d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1358d5ac70f0Sopenharmony_ci return -EINVAL; 1359d5ac70f0Sopenharmony_ci } 1360d5ac70f0Sopenharmony_ci 1361d5ac70f0Sopenharmony_ci err = determine_chmap(tt, &tt_chmap); 1362d5ac70f0Sopenharmony_ci if (err < 0) { 1363d5ac70f0Sopenharmony_ci free(ttable); 1364d5ac70f0Sopenharmony_ci return err; 1365d5ac70f0Sopenharmony_ci } 1366d5ac70f0Sopenharmony_ci 1367d5ac70f0Sopenharmony_ci err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 1368d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1369d5ac70f0Sopenharmony_ci if (err < 0) { 1370d5ac70f0Sopenharmony_ci free(tt_chmap); 1371d5ac70f0Sopenharmony_ci free(ttable); 1372d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1373d5ac70f0Sopenharmony_ci return err; 1374d5ac70f0Sopenharmony_ci } 1375d5ac70f0Sopenharmony_ci 1376d5ac70f0Sopenharmony_ci if (tt_chmap) { 1377d5ac70f0Sopenharmony_ci if (!chmaps) 1378d5ac70f0Sopenharmony_ci chmaps = snd_pcm_query_chmaps(spcm); 1379d5ac70f0Sopenharmony_ci if (chmaps) 1380d5ac70f0Sopenharmony_ci err = find_matching_chmap(chmaps, tt_chmap, &chmap, 1381d5ac70f0Sopenharmony_ci &schannels); 1382d5ac70f0Sopenharmony_ci free(tt_chmap); 1383d5ac70f0Sopenharmony_ci if (chmaps && err < 0) { 1384d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1385d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1386d5ac70f0Sopenharmony_ci return err; 1387d5ac70f0Sopenharmony_ci } 1388d5ac70f0Sopenharmony_ci } 1389d5ac70f0Sopenharmony_ci 1390d5ac70f0Sopenharmony_ci err = _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap); 1391d5ac70f0Sopenharmony_ci if (err < 0) { 1392d5ac70f0Sopenharmony_ci free(chmap); 1393d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1394d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1395d5ac70f0Sopenharmony_ci return err; 1396d5ac70f0Sopenharmony_ci } 1397d5ac70f0Sopenharmony_ci ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t)); 1398d5ac70f0Sopenharmony_ci if (ttable == NULL) { 1399d5ac70f0Sopenharmony_ci free(chmap); 1400d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1401d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1402d5ac70f0Sopenharmony_ci return -ENOMEM; 1403d5ac70f0Sopenharmony_ci } 1404d5ac70f0Sopenharmony_ci err = _snd_pcm_route_load_ttable(tt, ttable, csize, ssize, 1405d5ac70f0Sopenharmony_ci &cused, &sused, schannels, chmap); 1406d5ac70f0Sopenharmony_ci if (err < 0) { 1407d5ac70f0Sopenharmony_ci free(chmap); 1408d5ac70f0Sopenharmony_ci free(ttable); 1409d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1410d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1411d5ac70f0Sopenharmony_ci return err; 1412d5ac70f0Sopenharmony_ci } 1413d5ac70f0Sopenharmony_ci 1414d5ac70f0Sopenharmony_ci err = snd_pcm_route_open(pcmp, name, sformat, schannels, 1415d5ac70f0Sopenharmony_ci ttable, ssize, 1416d5ac70f0Sopenharmony_ci cused, sused, 1417d5ac70f0Sopenharmony_ci spcm, 1); 1418d5ac70f0Sopenharmony_ci free(ttable); 1419d5ac70f0Sopenharmony_ci if (err < 0) { 1420d5ac70f0Sopenharmony_ci free(chmap); 1421d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmaps); 1422d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1423d5ac70f0Sopenharmony_ci } else { 1424d5ac70f0Sopenharmony_ci snd_pcm_route_t *route = (*pcmp)->private_data; 1425d5ac70f0Sopenharmony_ci 1426d5ac70f0Sopenharmony_ci route->chmap = chmap; 1427d5ac70f0Sopenharmony_ci route->chmap_override = chmaps; 1428d5ac70f0Sopenharmony_ci } 1429d5ac70f0Sopenharmony_ci 1430d5ac70f0Sopenharmony_ci return err; 1431d5ac70f0Sopenharmony_ci} 1432d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 1433d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_route_open, SND_PCM_DLSYM_VERSION); 1434d5ac70f0Sopenharmony_ci#endif 1435