1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci * PCM - Params functions 3d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 4d5ac70f0Sopenharmony_ci * 5d5ac70f0Sopenharmony_ci * 6d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 7d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 8d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 9d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 10d5ac70f0Sopenharmony_ci * 11d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 12d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 15d5ac70f0Sopenharmony_ci * 16d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 18d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19d5ac70f0Sopenharmony_ci * 20d5ac70f0Sopenharmony_ci */ 21d5ac70f0Sopenharmony_ci 22d5ac70f0Sopenharmony_ci#include "pcm_local.h" 23d5ac70f0Sopenharmony_ci 24d5ac70f0Sopenharmony_ci#ifndef NDEBUG 25d5ac70f0Sopenharmony_ci/* 26d5ac70f0Sopenharmony_ci * dump hw_params when $LIBASOUND_DEBUG is set to >= 1 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_cistatic void dump_hw_params(snd_pcm_hw_params_t *params, const char *type, 29d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int val, int err) 30d5ac70f0Sopenharmony_ci{ 31d5ac70f0Sopenharmony_ci const char *verbose = getenv("LIBASOUND_DEBUG"); 32d5ac70f0Sopenharmony_ci snd_output_t *out; 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ci if (! verbose || ! *verbose || atoi(verbose) < 1) 35d5ac70f0Sopenharmony_ci return; 36d5ac70f0Sopenharmony_ci if (snd_output_stdio_attach(&out, stderr, 0) < 0) 37d5ac70f0Sopenharmony_ci return; 38d5ac70f0Sopenharmony_ci fprintf(stderr, "ALSA ERROR hw_params: %s (%s)\n", 39d5ac70f0Sopenharmony_ci type, snd_pcm_hw_param_name(var)); 40d5ac70f0Sopenharmony_ci fprintf(stderr, " value = "); 41d5ac70f0Sopenharmony_ci switch (var) { 42d5ac70f0Sopenharmony_ci case SND_PCM_HW_PARAM_ACCESS: 43d5ac70f0Sopenharmony_ci fprintf(stderr, "%s", snd_pcm_access_name(val)); 44d5ac70f0Sopenharmony_ci break; 45d5ac70f0Sopenharmony_ci case SND_PCM_HW_PARAM_FORMAT: 46d5ac70f0Sopenharmony_ci fprintf(stderr, "%s", snd_pcm_format_name(val)); 47d5ac70f0Sopenharmony_ci break; 48d5ac70f0Sopenharmony_ci case SND_PCM_HW_PARAM_SUBFORMAT: 49d5ac70f0Sopenharmony_ci fprintf(stderr, "%s", snd_pcm_subformat_name(val)); 50d5ac70f0Sopenharmony_ci break; 51d5ac70f0Sopenharmony_ci default: 52d5ac70f0Sopenharmony_ci fprintf(stderr, "%u", val); 53d5ac70f0Sopenharmony_ci } 54d5ac70f0Sopenharmony_ci fprintf(stderr, " : %s\n", snd_strerror(err)); 55d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, out); 56d5ac70f0Sopenharmony_ci snd_output_close(out); 57d5ac70f0Sopenharmony_ci} 58d5ac70f0Sopenharmony_ci#else 59d5ac70f0Sopenharmony_cistatic inline void dump_hw_params(snd_pcm_hw_params_t *params, const char *type, 60d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int val, int err) 61d5ac70f0Sopenharmony_ci{ 62d5ac70f0Sopenharmony_ci} 63d5ac70f0Sopenharmony_ci#endif 64d5ac70f0Sopenharmony_ci 65d5ac70f0Sopenharmony_cistatic inline int hw_is_mask(snd_pcm_hw_param_t var) 66d5ac70f0Sopenharmony_ci{ 67d5ac70f0Sopenharmony_ci#if SND_PCM_HW_PARAM_FIRST_MASK == 0 68d5ac70f0Sopenharmony_ci return var <= SND_PCM_HW_PARAM_LAST_MASK; 69d5ac70f0Sopenharmony_ci#else 70d5ac70f0Sopenharmony_ci return var >= SND_PCM_HW_PARAM_FIRST_MASK && 71d5ac70f0Sopenharmony_ci var <= SND_PCM_HW_PARAM_LAST_MASK; 72d5ac70f0Sopenharmony_ci#endif 73d5ac70f0Sopenharmony_ci} 74d5ac70f0Sopenharmony_ci 75d5ac70f0Sopenharmony_cistatic inline int hw_is_interval(snd_pcm_hw_param_t var) 76d5ac70f0Sopenharmony_ci{ 77d5ac70f0Sopenharmony_ci return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL && 78d5ac70f0Sopenharmony_ci var <= SND_PCM_HW_PARAM_LAST_INTERVAL; 79d5ac70f0Sopenharmony_ci} 80d5ac70f0Sopenharmony_ci 81d5ac70f0Sopenharmony_ci#define hw_param_mask(params,var) \ 82d5ac70f0Sopenharmony_ci &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK]) 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci#define hw_param_interval(params,var) \ 85d5ac70f0Sopenharmony_ci &((params)->intervals[(var) - SND_PCM_HW_PARAM_FIRST_INTERVAL]) 86d5ac70f0Sopenharmony_ci 87d5ac70f0Sopenharmony_ci#define hw_param_mask_c hw_param_mask 88d5ac70f0Sopenharmony_ci#define hw_param_interval_c hw_param_interval 89d5ac70f0Sopenharmony_ci 90d5ac70f0Sopenharmony_cistatic void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) 91d5ac70f0Sopenharmony_ci{ 92d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 93d5ac70f0Sopenharmony_ci snd_mask_any(hw_param_mask(params, var)); 94d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 95d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 96d5ac70f0Sopenharmony_ci return; 97d5ac70f0Sopenharmony_ci } 98d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) { 99d5ac70f0Sopenharmony_ci snd_interval_any(hw_param_interval(params, var)); 100d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 101d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 102d5ac70f0Sopenharmony_ci return; 103d5ac70f0Sopenharmony_ci } 104d5ac70f0Sopenharmony_ci assert(0); 105d5ac70f0Sopenharmony_ci} 106d5ac70f0Sopenharmony_ci 107d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 108d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 109d5ac70f0Sopenharmony_ci{ 110d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_any(params, var); 111d5ac70f0Sopenharmony_ci return snd_pcm_hw_refine(pcm, params); 112d5ac70f0Sopenharmony_ci} 113d5ac70f0Sopenharmony_ci 114d5ac70f0Sopenharmony_civoid _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) 115d5ac70f0Sopenharmony_ci{ 116d5ac70f0Sopenharmony_ci unsigned int k; 117d5ac70f0Sopenharmony_ci memset(params, 0, sizeof(*params)); 118d5ac70f0Sopenharmony_ci for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) 119d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_any(params, k); 120d5ac70f0Sopenharmony_ci for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) 121d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_any(params, k); 122d5ac70f0Sopenharmony_ci params->rmask = ~0U; 123d5ac70f0Sopenharmony_ci params->cmask = 0; 124d5ac70f0Sopenharmony_ci params->info = ~0U; 125d5ac70f0Sopenharmony_ci} 126d5ac70f0Sopenharmony_ci 127d5ac70f0Sopenharmony_ci/* Return the value for field PAR if it's fixed in configuration space 128d5ac70f0Sopenharmony_ci defined by PARAMS. Return -EINVAL otherwise 129d5ac70f0Sopenharmony_ci*/ 130d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_get(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, 131d5ac70f0Sopenharmony_ci unsigned int *val, int *dir) 132d5ac70f0Sopenharmony_ci{ 133d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 134d5ac70f0Sopenharmony_ci const snd_mask_t *mask = hw_param_mask_c(params, var); 135d5ac70f0Sopenharmony_ci if (snd_mask_empty(mask) || !snd_mask_single(mask)) 136d5ac70f0Sopenharmony_ci return -EINVAL; 137d5ac70f0Sopenharmony_ci if (dir) 138d5ac70f0Sopenharmony_ci *dir = 0; 139d5ac70f0Sopenharmony_ci if (val) 140d5ac70f0Sopenharmony_ci *val = snd_mask_value(mask); 141d5ac70f0Sopenharmony_ci return 0; 142d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) { 143d5ac70f0Sopenharmony_ci const snd_interval_t *i = hw_param_interval_c(params, var); 144d5ac70f0Sopenharmony_ci if (snd_interval_empty(i) || !snd_interval_single(i)) 145d5ac70f0Sopenharmony_ci return -EINVAL; 146d5ac70f0Sopenharmony_ci if (dir) 147d5ac70f0Sopenharmony_ci *dir = i->openmin; 148d5ac70f0Sopenharmony_ci if (val) 149d5ac70f0Sopenharmony_ci *val = snd_interval_value(i); 150d5ac70f0Sopenharmony_ci return 0; 151d5ac70f0Sopenharmony_ci } 152d5ac70f0Sopenharmony_ci assert(0); 153d5ac70f0Sopenharmony_ci return -EINVAL; 154d5ac70f0Sopenharmony_ci} 155d5ac70f0Sopenharmony_ci 156d5ac70f0Sopenharmony_ci/* Return the minimum value for field PAR. */ 157d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, 158d5ac70f0Sopenharmony_ci unsigned int *val, int *dir) 159d5ac70f0Sopenharmony_ci{ 160d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 161d5ac70f0Sopenharmony_ci const snd_mask_t *m = hw_param_mask_c(params, var); 162d5ac70f0Sopenharmony_ci assert(!snd_mask_empty(m)); 163d5ac70f0Sopenharmony_ci if (dir) 164d5ac70f0Sopenharmony_ci *dir = 0; 165d5ac70f0Sopenharmony_ci if (val) 166d5ac70f0Sopenharmony_ci *val = snd_mask_min(m); 167d5ac70f0Sopenharmony_ci return 0; 168d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) { 169d5ac70f0Sopenharmony_ci const snd_interval_t *i = hw_param_interval_c(params, var); 170d5ac70f0Sopenharmony_ci assert(!snd_interval_empty(i)); 171d5ac70f0Sopenharmony_ci if (dir) 172d5ac70f0Sopenharmony_ci *dir = i->openmin; 173d5ac70f0Sopenharmony_ci if (val) 174d5ac70f0Sopenharmony_ci *val = snd_interval_min(i); 175d5ac70f0Sopenharmony_ci return 0; 176d5ac70f0Sopenharmony_ci } 177d5ac70f0Sopenharmony_ci assert(0); 178d5ac70f0Sopenharmony_ci return 0; 179d5ac70f0Sopenharmony_ci} 180d5ac70f0Sopenharmony_ci 181d5ac70f0Sopenharmony_ci/* Return the maximum value for field PAR. */ 182d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, 183d5ac70f0Sopenharmony_ci unsigned int *val, int *dir) 184d5ac70f0Sopenharmony_ci{ 185d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 186d5ac70f0Sopenharmony_ci const snd_mask_t *m = hw_param_mask_c(params, var); 187d5ac70f0Sopenharmony_ci assert(!snd_mask_empty(m)); 188d5ac70f0Sopenharmony_ci if (dir) 189d5ac70f0Sopenharmony_ci *dir = 0; 190d5ac70f0Sopenharmony_ci if (val) 191d5ac70f0Sopenharmony_ci *val = snd_mask_max(m); 192d5ac70f0Sopenharmony_ci return 0; 193d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) { 194d5ac70f0Sopenharmony_ci const snd_interval_t *i = hw_param_interval_c(params, var); 195d5ac70f0Sopenharmony_ci assert(!snd_interval_empty(i)); 196d5ac70f0Sopenharmony_ci if (dir) 197d5ac70f0Sopenharmony_ci *dir = - (int) i->openmax; 198d5ac70f0Sopenharmony_ci if (val) 199d5ac70f0Sopenharmony_ci *val = snd_interval_max(i); 200d5ac70f0Sopenharmony_ci return 0; 201d5ac70f0Sopenharmony_ci } 202d5ac70f0Sopenharmony_ci assert(0); 203d5ac70f0Sopenharmony_ci return 0; 204d5ac70f0Sopenharmony_ci} 205d5ac70f0Sopenharmony_ci 206d5ac70f0Sopenharmony_ci/* Return the mask for field PAR. 207d5ac70f0Sopenharmony_ci This function can be called only for SND_PCM_HW_PARAM_ACCESS, 208d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */ 209d5ac70f0Sopenharmony_ciconst snd_mask_t *snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t *params, 210d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 211d5ac70f0Sopenharmony_ci{ 212d5ac70f0Sopenharmony_ci assert(hw_is_mask(var)); 213d5ac70f0Sopenharmony_ci return hw_param_mask_c(params, var); 214d5ac70f0Sopenharmony_ci} 215d5ac70f0Sopenharmony_ci 216d5ac70f0Sopenharmony_ci/* Return the interval for field PAR. 217d5ac70f0Sopenharmony_ci This function cannot be called for SND_PCM_HW_PARAM_ACCESS, 218d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */ 219d5ac70f0Sopenharmony_ciconst snd_interval_t *snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t *params, 220d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 221d5ac70f0Sopenharmony_ci{ 222d5ac70f0Sopenharmony_ci assert(hw_is_interval(var)); 223d5ac70f0Sopenharmony_ci return hw_param_interval_c(params, var); 224d5ac70f0Sopenharmony_ci} 225d5ac70f0Sopenharmony_ci 226d5ac70f0Sopenharmony_ci/* --- Refinement functions --- */ 227d5ac70f0Sopenharmony_ci 228d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t *params, 229d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 230d5ac70f0Sopenharmony_ci const snd_interval_t *val) 231d5ac70f0Sopenharmony_ci{ 232d5ac70f0Sopenharmony_ci int changed; 233d5ac70f0Sopenharmony_ci assert(hw_is_interval(var)); 234d5ac70f0Sopenharmony_ci changed = snd_interval_refine(hw_param_interval(params, var), val); 235d5ac70f0Sopenharmony_ci if (changed) { 236d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 237d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 238d5ac70f0Sopenharmony_ci } 239d5ac70f0Sopenharmony_ci return changed; 240d5ac70f0Sopenharmony_ci} 241d5ac70f0Sopenharmony_ci 242d5ac70f0Sopenharmony_civoid _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params, 243d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 244d5ac70f0Sopenharmony_ci{ 245d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 246d5ac70f0Sopenharmony_ci snd_mask_none(hw_param_mask(params, var)); 247d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 248d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 249d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) { 250d5ac70f0Sopenharmony_ci snd_interval_none(hw_param_interval(params, var)); 251d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 252d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 253d5ac70f0Sopenharmony_ci } else { 254d5ac70f0Sopenharmony_ci assert(0); 255d5ac70f0Sopenharmony_ci } 256d5ac70f0Sopenharmony_ci} 257d5ac70f0Sopenharmony_ci 258d5ac70f0Sopenharmony_cistatic int _snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t *params, 259d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 260d5ac70f0Sopenharmony_ci{ 261d5ac70f0Sopenharmony_ci int changed; 262d5ac70f0Sopenharmony_ci assert(hw_is_interval(var)); 263d5ac70f0Sopenharmony_ci changed = snd_interval_setinteger(hw_param_interval(params, var)); 264d5ac70f0Sopenharmony_ci if (changed) { 265d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 266d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 267d5ac70f0Sopenharmony_ci } 268d5ac70f0Sopenharmony_ci return changed; 269d5ac70f0Sopenharmony_ci} 270d5ac70f0Sopenharmony_ci 271d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 272d5ac70f0Sopenharmony_ci non integer values. Reduce configuration space accordingly. 273d5ac70f0Sopenharmony_ci Return -EINVAL if the configuration space is empty 274d5ac70f0Sopenharmony_ci*/ 275d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_integer(snd_pcm_t *pcm, 276d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 277d5ac70f0Sopenharmony_ci snd_set_mode_t mode, 278d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 279d5ac70f0Sopenharmony_ci{ 280d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 281d5ac70f0Sopenharmony_ci int err; 282d5ac70f0Sopenharmony_ci switch (mode) { 283d5ac70f0Sopenharmony_ci case SND_CHANGE: 284d5ac70f0Sopenharmony_ci break; 285d5ac70f0Sopenharmony_ci case SND_TRY: 286d5ac70f0Sopenharmony_ci save = *params; 287d5ac70f0Sopenharmony_ci break; 288d5ac70f0Sopenharmony_ci case SND_TEST: 289d5ac70f0Sopenharmony_ci save = *params; 290d5ac70f0Sopenharmony_ci params = &save; 291d5ac70f0Sopenharmony_ci break; 292d5ac70f0Sopenharmony_ci default: 293d5ac70f0Sopenharmony_ci assert(0); 294d5ac70f0Sopenharmony_ci return -EINVAL; 295d5ac70f0Sopenharmony_ci } 296d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_integer(params, var); 297d5ac70f0Sopenharmony_ci if (err < 0) 298d5ac70f0Sopenharmony_ci goto _fail; 299d5ac70f0Sopenharmony_ci if (params->rmask) { 300d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 301d5ac70f0Sopenharmony_ci if (err < 0) 302d5ac70f0Sopenharmony_ci goto _fail; 303d5ac70f0Sopenharmony_ci } 304d5ac70f0Sopenharmony_ci return 0; 305d5ac70f0Sopenharmony_ci _fail: 306d5ac70f0Sopenharmony_ci if (mode == SND_TRY) 307d5ac70f0Sopenharmony_ci *params = save; 308d5ac70f0Sopenharmony_ci return err; 309d5ac70f0Sopenharmony_ci} 310d5ac70f0Sopenharmony_ci 311d5ac70f0Sopenharmony_cistatic int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params, 312d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 313d5ac70f0Sopenharmony_ci{ 314d5ac70f0Sopenharmony_ci int changed; 315d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) 316d5ac70f0Sopenharmony_ci changed = snd_mask_refine_first(hw_param_mask(params, var)); 317d5ac70f0Sopenharmony_ci else if (hw_is_interval(var)) 318d5ac70f0Sopenharmony_ci changed = snd_interval_refine_first(hw_param_interval(params, var)); 319d5ac70f0Sopenharmony_ci else { 320d5ac70f0Sopenharmony_ci assert(0); 321d5ac70f0Sopenharmony_ci return -EINVAL; 322d5ac70f0Sopenharmony_ci } 323d5ac70f0Sopenharmony_ci if (changed > 0) { 324d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 325d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 326d5ac70f0Sopenharmony_ci } 327d5ac70f0Sopenharmony_ci return changed; 328d5ac70f0Sopenharmony_ci} 329d5ac70f0Sopenharmony_ci 330d5ac70f0Sopenharmony_ci 331d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 332d5ac70f0Sopenharmony_ci values > minimum. Reduce configuration space accordingly. 333d5ac70f0Sopenharmony_ci Return the minimum. 334d5ac70f0Sopenharmony_ci*/ 335d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_first(snd_pcm_t *pcm, 336d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 337d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 338d5ac70f0Sopenharmony_ci unsigned int *rval, int *dir) 339d5ac70f0Sopenharmony_ci{ 340d5ac70f0Sopenharmony_ci int err; 341d5ac70f0Sopenharmony_ci 342d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_first(params, var); 343d5ac70f0Sopenharmony_ci if (err < 0) 344d5ac70f0Sopenharmony_ci return err; 345d5ac70f0Sopenharmony_ci if (params->rmask) { 346d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 347d5ac70f0Sopenharmony_ci if (err < 0) 348d5ac70f0Sopenharmony_ci return err; 349d5ac70f0Sopenharmony_ci } 350d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_get(params, var, rval, dir); 351d5ac70f0Sopenharmony_ci} 352d5ac70f0Sopenharmony_ci 353d5ac70f0Sopenharmony_cistatic int _snd_pcm_hw_param_set_last(snd_pcm_hw_params_t *params, 354d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 355d5ac70f0Sopenharmony_ci{ 356d5ac70f0Sopenharmony_ci int changed; 357d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) 358d5ac70f0Sopenharmony_ci changed = snd_mask_refine_last(hw_param_mask(params, var)); 359d5ac70f0Sopenharmony_ci else if (hw_is_interval(var)) 360d5ac70f0Sopenharmony_ci changed = snd_interval_refine_last(hw_param_interval(params, var)); 361d5ac70f0Sopenharmony_ci else { 362d5ac70f0Sopenharmony_ci assert(0); 363d5ac70f0Sopenharmony_ci return -EINVAL; 364d5ac70f0Sopenharmony_ci } 365d5ac70f0Sopenharmony_ci if (changed > 0) { 366d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 367d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 368d5ac70f0Sopenharmony_ci } 369d5ac70f0Sopenharmony_ci return changed; 370d5ac70f0Sopenharmony_ci} 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_ci 373d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 374d5ac70f0Sopenharmony_ci values < maximum. Reduce configuration space accordingly. 375d5ac70f0Sopenharmony_ci Return the maximum. 376d5ac70f0Sopenharmony_ci*/ 377d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_last(snd_pcm_t *pcm, 378d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 379d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 380d5ac70f0Sopenharmony_ci unsigned int *rval, int *dir) 381d5ac70f0Sopenharmony_ci{ 382d5ac70f0Sopenharmony_ci int err; 383d5ac70f0Sopenharmony_ci 384d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_last(params, var); 385d5ac70f0Sopenharmony_ci if (err < 0) 386d5ac70f0Sopenharmony_ci return err; 387d5ac70f0Sopenharmony_ci if (params->rmask) { 388d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 389d5ac70f0Sopenharmony_ci if (err < 0) 390d5ac70f0Sopenharmony_ci return err; 391d5ac70f0Sopenharmony_ci } 392d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_get(params, var, rval, dir); 393d5ac70f0Sopenharmony_ci} 394d5ac70f0Sopenharmony_ci 395d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params, 396d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int val, int dir) 397d5ac70f0Sopenharmony_ci{ 398d5ac70f0Sopenharmony_ci int changed; 399d5ac70f0Sopenharmony_ci int openmin = 0; 400d5ac70f0Sopenharmony_ci if (dir) { 401d5ac70f0Sopenharmony_ci if (dir > 0) { 402d5ac70f0Sopenharmony_ci openmin = 1; 403d5ac70f0Sopenharmony_ci } else if (dir < 0) { 404d5ac70f0Sopenharmony_ci if (val > 0) { 405d5ac70f0Sopenharmony_ci openmin = 1; 406d5ac70f0Sopenharmony_ci val--; 407d5ac70f0Sopenharmony_ci } 408d5ac70f0Sopenharmony_ci } 409d5ac70f0Sopenharmony_ci } 410d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) 411d5ac70f0Sopenharmony_ci changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!openmin); 412d5ac70f0Sopenharmony_ci else if (hw_is_interval(var)) 413d5ac70f0Sopenharmony_ci changed = snd_interval_refine_min(hw_param_interval(params, var), val, openmin); 414d5ac70f0Sopenharmony_ci else { 415d5ac70f0Sopenharmony_ci assert(0); 416d5ac70f0Sopenharmony_ci return -EINVAL; 417d5ac70f0Sopenharmony_ci } 418d5ac70f0Sopenharmony_ci if (changed) { 419d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 420d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 421d5ac70f0Sopenharmony_ci } 422d5ac70f0Sopenharmony_ci return changed; 423d5ac70f0Sopenharmony_ci} 424d5ac70f0Sopenharmony_ci 425d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 426d5ac70f0Sopenharmony_ci values < VAL. Reduce configuration space accordingly. 427d5ac70f0Sopenharmony_ci Return new minimum or -EINVAL if the configuration space is empty 428d5ac70f0Sopenharmony_ci*/ 429d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 430d5ac70f0Sopenharmony_ci snd_set_mode_t mode, 431d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int *val, int *dir) 432d5ac70f0Sopenharmony_ci{ 433d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 434d5ac70f0Sopenharmony_ci int err; 435d5ac70f0Sopenharmony_ci switch (mode) { 436d5ac70f0Sopenharmony_ci case SND_CHANGE: 437d5ac70f0Sopenharmony_ci break; 438d5ac70f0Sopenharmony_ci case SND_TRY: 439d5ac70f0Sopenharmony_ci save = *params; 440d5ac70f0Sopenharmony_ci break; 441d5ac70f0Sopenharmony_ci case SND_TEST: 442d5ac70f0Sopenharmony_ci save = *params; 443d5ac70f0Sopenharmony_ci params = &save; 444d5ac70f0Sopenharmony_ci break; 445d5ac70f0Sopenharmony_ci default: 446d5ac70f0Sopenharmony_ci assert(0); 447d5ac70f0Sopenharmony_ci return -EINVAL; 448d5ac70f0Sopenharmony_ci } 449d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_min(params, var, *val, dir ? *dir : 0); 450d5ac70f0Sopenharmony_ci if (err < 0) 451d5ac70f0Sopenharmony_ci goto _fail; 452d5ac70f0Sopenharmony_ci if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { 453d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 454d5ac70f0Sopenharmony_ci if (err < 0) 455d5ac70f0Sopenharmony_ci goto _fail; 456d5ac70f0Sopenharmony_ci if (snd_pcm_hw_param_empty(params, var)) { 457d5ac70f0Sopenharmony_ci err = -ENOENT; 458d5ac70f0Sopenharmony_ci goto _fail; 459d5ac70f0Sopenharmony_ci } 460d5ac70f0Sopenharmony_ci } 461d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_get_min(params, var, val, dir); 462d5ac70f0Sopenharmony_ci _fail: 463d5ac70f0Sopenharmony_ci if (mode == SND_TRY) 464d5ac70f0Sopenharmony_ci *params = save; 465d5ac70f0Sopenharmony_ci if (err < 0 && mode == SND_TRY) 466d5ac70f0Sopenharmony_ci dump_hw_params(params, "set_min", var, *val, err); 467d5ac70f0Sopenharmony_ci return err; 468d5ac70f0Sopenharmony_ci} 469d5ac70f0Sopenharmony_ci 470d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_set_max(snd_pcm_hw_params_t *params, 471d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int val, int dir) 472d5ac70f0Sopenharmony_ci{ 473d5ac70f0Sopenharmony_ci int changed; 474d5ac70f0Sopenharmony_ci int openmax = 0; 475d5ac70f0Sopenharmony_ci if (dir) { 476d5ac70f0Sopenharmony_ci if (dir < 0) { 477d5ac70f0Sopenharmony_ci openmax = 1; 478d5ac70f0Sopenharmony_ci } else if (dir > 0) { 479d5ac70f0Sopenharmony_ci openmax = 1; 480d5ac70f0Sopenharmony_ci val++; 481d5ac70f0Sopenharmony_ci } 482d5ac70f0Sopenharmony_ci } 483d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 484d5ac70f0Sopenharmony_ci if (val == 0 && openmax) { 485d5ac70f0Sopenharmony_ci snd_mask_none(hw_param_mask(params, var)); 486d5ac70f0Sopenharmony_ci changed = -EINVAL; 487d5ac70f0Sopenharmony_ci } else 488d5ac70f0Sopenharmony_ci changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!openmax); 489d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) 490d5ac70f0Sopenharmony_ci changed = snd_interval_refine_max(hw_param_interval(params, var), val, openmax); 491d5ac70f0Sopenharmony_ci else { 492d5ac70f0Sopenharmony_ci assert(0); 493d5ac70f0Sopenharmony_ci return -EINVAL; 494d5ac70f0Sopenharmony_ci } 495d5ac70f0Sopenharmony_ci if (changed) { 496d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 497d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 498d5ac70f0Sopenharmony_ci } 499d5ac70f0Sopenharmony_ci return changed; 500d5ac70f0Sopenharmony_ci} 501d5ac70f0Sopenharmony_ci 502d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 503d5ac70f0Sopenharmony_ci values >= VAL + 1. Reduce configuration space accordingly. 504d5ac70f0Sopenharmony_ci Return new maximum or -EINVAL if the configuration space is empty 505d5ac70f0Sopenharmony_ci*/ 506d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 507d5ac70f0Sopenharmony_ci snd_set_mode_t mode, 508d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int *val, int *dir) 509d5ac70f0Sopenharmony_ci{ 510d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 511d5ac70f0Sopenharmony_ci int err; 512d5ac70f0Sopenharmony_ci switch (mode) { 513d5ac70f0Sopenharmony_ci case SND_CHANGE: 514d5ac70f0Sopenharmony_ci break; 515d5ac70f0Sopenharmony_ci case SND_TRY: 516d5ac70f0Sopenharmony_ci save = *params; 517d5ac70f0Sopenharmony_ci break; 518d5ac70f0Sopenharmony_ci case SND_TEST: 519d5ac70f0Sopenharmony_ci save = *params; 520d5ac70f0Sopenharmony_ci params = &save; 521d5ac70f0Sopenharmony_ci break; 522d5ac70f0Sopenharmony_ci default: 523d5ac70f0Sopenharmony_ci assert(0); 524d5ac70f0Sopenharmony_ci return -EINVAL; 525d5ac70f0Sopenharmony_ci } 526d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_max(params, var, *val, dir ? *dir : 0); 527d5ac70f0Sopenharmony_ci if (err < 0) 528d5ac70f0Sopenharmony_ci goto _fail; 529d5ac70f0Sopenharmony_ci if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { 530d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 531d5ac70f0Sopenharmony_ci if (err < 0) 532d5ac70f0Sopenharmony_ci goto _fail; 533d5ac70f0Sopenharmony_ci if (snd_pcm_hw_param_empty(params, var)) { 534d5ac70f0Sopenharmony_ci err = -ENOENT; 535d5ac70f0Sopenharmony_ci goto _fail; 536d5ac70f0Sopenharmony_ci } 537d5ac70f0Sopenharmony_ci } 538d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_get_max(params, var, val, dir); 539d5ac70f0Sopenharmony_ci _fail: 540d5ac70f0Sopenharmony_ci if (mode == SND_TRY) 541d5ac70f0Sopenharmony_ci *params = save; 542d5ac70f0Sopenharmony_ci if (err < 0 && mode == SND_TRY) 543d5ac70f0Sopenharmony_ci dump_hw_params(params, "set_max", var, *val, err); 544d5ac70f0Sopenharmony_ci return err; 545d5ac70f0Sopenharmony_ci} 546d5ac70f0Sopenharmony_ci 547d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t *params, 548d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 549d5ac70f0Sopenharmony_ci unsigned int min, int mindir, 550d5ac70f0Sopenharmony_ci unsigned int max, int maxdir) 551d5ac70f0Sopenharmony_ci{ 552d5ac70f0Sopenharmony_ci int changed, c1, c2; 553d5ac70f0Sopenharmony_ci int openmin = 0, openmax = 0; 554d5ac70f0Sopenharmony_ci if (mindir) { 555d5ac70f0Sopenharmony_ci if (mindir > 0) { 556d5ac70f0Sopenharmony_ci openmin = 1; 557d5ac70f0Sopenharmony_ci } else if (mindir < 0) { 558d5ac70f0Sopenharmony_ci if (min > 0) { 559d5ac70f0Sopenharmony_ci openmin = 1; 560d5ac70f0Sopenharmony_ci min--; 561d5ac70f0Sopenharmony_ci } 562d5ac70f0Sopenharmony_ci } 563d5ac70f0Sopenharmony_ci } 564d5ac70f0Sopenharmony_ci if (maxdir) { 565d5ac70f0Sopenharmony_ci if (maxdir < 0) { 566d5ac70f0Sopenharmony_ci openmax = 1; 567d5ac70f0Sopenharmony_ci } else if (maxdir > 0) { 568d5ac70f0Sopenharmony_ci openmax = 1; 569d5ac70f0Sopenharmony_ci max++; 570d5ac70f0Sopenharmony_ci } 571d5ac70f0Sopenharmony_ci } 572d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 573d5ac70f0Sopenharmony_ci snd_mask_t *mask = hw_param_mask(params, var); 574d5ac70f0Sopenharmony_ci if (max == 0 && openmax) { 575d5ac70f0Sopenharmony_ci snd_mask_none(mask); 576d5ac70f0Sopenharmony_ci changed = -EINVAL; 577d5ac70f0Sopenharmony_ci } else { 578d5ac70f0Sopenharmony_ci c1 = snd_mask_refine_min(mask, min + !!openmin); 579d5ac70f0Sopenharmony_ci if (c1 < 0) 580d5ac70f0Sopenharmony_ci changed = c1; 581d5ac70f0Sopenharmony_ci else { 582d5ac70f0Sopenharmony_ci c2 = snd_mask_refine_max(mask, max - !!openmax); 583d5ac70f0Sopenharmony_ci if (c2 < 0) 584d5ac70f0Sopenharmony_ci changed = c2; 585d5ac70f0Sopenharmony_ci else 586d5ac70f0Sopenharmony_ci changed = (c1 || c2); 587d5ac70f0Sopenharmony_ci } 588d5ac70f0Sopenharmony_ci } 589d5ac70f0Sopenharmony_ci } 590d5ac70f0Sopenharmony_ci else if (hw_is_interval(var)) { 591d5ac70f0Sopenharmony_ci snd_interval_t *i = hw_param_interval(params, var); 592d5ac70f0Sopenharmony_ci c1 = snd_interval_refine_min(i, min, openmin); 593d5ac70f0Sopenharmony_ci if (c1 < 0) 594d5ac70f0Sopenharmony_ci changed = c1; 595d5ac70f0Sopenharmony_ci else { 596d5ac70f0Sopenharmony_ci c2 = snd_interval_refine_max(i, max, openmax); 597d5ac70f0Sopenharmony_ci if (c2 < 0) 598d5ac70f0Sopenharmony_ci changed = c2; 599d5ac70f0Sopenharmony_ci else 600d5ac70f0Sopenharmony_ci changed = (c1 || c2); 601d5ac70f0Sopenharmony_ci } 602d5ac70f0Sopenharmony_ci } else { 603d5ac70f0Sopenharmony_ci assert(0); 604d5ac70f0Sopenharmony_ci return -EINVAL; 605d5ac70f0Sopenharmony_ci } 606d5ac70f0Sopenharmony_ci if (changed) { 607d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 608d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 609d5ac70f0Sopenharmony_ci } 610d5ac70f0Sopenharmony_ci return changed; 611d5ac70f0Sopenharmony_ci} 612d5ac70f0Sopenharmony_ci 613d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 614d5ac70f0Sopenharmony_ci values < MIN and all values > MAX. Reduce configuration space accordingly. 615d5ac70f0Sopenharmony_ci Return 0 or -EINVAL if the configuration space is empty 616d5ac70f0Sopenharmony_ci*/ 617d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 618d5ac70f0Sopenharmony_ci snd_set_mode_t mode, 619d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 620d5ac70f0Sopenharmony_ci unsigned int *min, int *mindir, 621d5ac70f0Sopenharmony_ci unsigned int *max, int *maxdir) 622d5ac70f0Sopenharmony_ci{ 623d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 624d5ac70f0Sopenharmony_ci int err; 625d5ac70f0Sopenharmony_ci switch (mode) { 626d5ac70f0Sopenharmony_ci case SND_CHANGE: 627d5ac70f0Sopenharmony_ci break; 628d5ac70f0Sopenharmony_ci case SND_TRY: 629d5ac70f0Sopenharmony_ci save = *params; 630d5ac70f0Sopenharmony_ci break; 631d5ac70f0Sopenharmony_ci case SND_TEST: 632d5ac70f0Sopenharmony_ci save = *params; 633d5ac70f0Sopenharmony_ci params = &save; 634d5ac70f0Sopenharmony_ci break; 635d5ac70f0Sopenharmony_ci default: 636d5ac70f0Sopenharmony_ci assert(0); 637d5ac70f0Sopenharmony_ci return -EINVAL; 638d5ac70f0Sopenharmony_ci } 639d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_minmax(params, var, 640d5ac70f0Sopenharmony_ci *min, mindir ? *mindir : 0, 641d5ac70f0Sopenharmony_ci *max, maxdir ? *maxdir : 0); 642d5ac70f0Sopenharmony_ci if (err < 0) 643d5ac70f0Sopenharmony_ci goto _fail; 644d5ac70f0Sopenharmony_ci if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { 645d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 646d5ac70f0Sopenharmony_ci if (err < 0) 647d5ac70f0Sopenharmony_ci goto _fail; 648d5ac70f0Sopenharmony_ci } 649d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_get_min(params, var, min, mindir); 650d5ac70f0Sopenharmony_ci if (err < 0) 651d5ac70f0Sopenharmony_ci return err; 652d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_get_max(params, var, max, maxdir); 653d5ac70f0Sopenharmony_ci _fail: 654d5ac70f0Sopenharmony_ci if (mode == SND_TRY) 655d5ac70f0Sopenharmony_ci *params = save; 656d5ac70f0Sopenharmony_ci if (err < 0) 657d5ac70f0Sopenharmony_ci dump_hw_params(params, "set_minmax", var, *min, err); 658d5ac70f0Sopenharmony_ci return err; 659d5ac70f0Sopenharmony_ci} 660d5ac70f0Sopenharmony_ci 661d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params, 662d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int val, int dir) 663d5ac70f0Sopenharmony_ci{ 664d5ac70f0Sopenharmony_ci int changed; 665d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 666d5ac70f0Sopenharmony_ci snd_mask_t *m = hw_param_mask(params, var); 667d5ac70f0Sopenharmony_ci if (val == 0 && dir < 0) { 668d5ac70f0Sopenharmony_ci changed = -EINVAL; 669d5ac70f0Sopenharmony_ci snd_mask_none(m); 670d5ac70f0Sopenharmony_ci } else { 671d5ac70f0Sopenharmony_ci if (dir > 0) 672d5ac70f0Sopenharmony_ci val++; 673d5ac70f0Sopenharmony_ci else if (dir < 0) 674d5ac70f0Sopenharmony_ci val--; 675d5ac70f0Sopenharmony_ci changed = snd_mask_refine_set(hw_param_mask(params, var), val); 676d5ac70f0Sopenharmony_ci } 677d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) { 678d5ac70f0Sopenharmony_ci snd_interval_t *i = hw_param_interval(params, var); 679d5ac70f0Sopenharmony_ci if (val == 0 && dir < 0) { 680d5ac70f0Sopenharmony_ci changed = -EINVAL; 681d5ac70f0Sopenharmony_ci snd_interval_none(i); 682d5ac70f0Sopenharmony_ci } else if (dir == 0) 683d5ac70f0Sopenharmony_ci changed = snd_interval_refine_set(i, val); 684d5ac70f0Sopenharmony_ci else { 685d5ac70f0Sopenharmony_ci snd_interval_t t; 686d5ac70f0Sopenharmony_ci t.openmin = 1; 687d5ac70f0Sopenharmony_ci t.openmax = 1; 688d5ac70f0Sopenharmony_ci t.empty = 0; 689d5ac70f0Sopenharmony_ci t.integer = 0; 690d5ac70f0Sopenharmony_ci if (dir < 0) { 691d5ac70f0Sopenharmony_ci t.min = val - 1; 692d5ac70f0Sopenharmony_ci t.max = val; 693d5ac70f0Sopenharmony_ci } else { 694d5ac70f0Sopenharmony_ci t.min = val; 695d5ac70f0Sopenharmony_ci t.max = val+1; 696d5ac70f0Sopenharmony_ci } 697d5ac70f0Sopenharmony_ci changed = snd_interval_refine(i, &t); 698d5ac70f0Sopenharmony_ci } 699d5ac70f0Sopenharmony_ci } else { 700d5ac70f0Sopenharmony_ci assert(0); 701d5ac70f0Sopenharmony_ci return -EINVAL; 702d5ac70f0Sopenharmony_ci } 703d5ac70f0Sopenharmony_ci if (changed) { 704d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 705d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 706d5ac70f0Sopenharmony_ci } 707d5ac70f0Sopenharmony_ci return changed; 708d5ac70f0Sopenharmony_ci} 709d5ac70f0Sopenharmony_ci 710d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all 711d5ac70f0Sopenharmony_ci values != VAL. Reduce configuration space accordingly. 712d5ac70f0Sopenharmony_ci Return -EINVAL if the configuration space is empty 713d5ac70f0Sopenharmony_ci*/ 714d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 715d5ac70f0Sopenharmony_ci snd_set_mode_t mode, 716d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, unsigned int val, int dir) 717d5ac70f0Sopenharmony_ci{ 718d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 719d5ac70f0Sopenharmony_ci int err; 720d5ac70f0Sopenharmony_ci switch (mode) { 721d5ac70f0Sopenharmony_ci case SND_CHANGE: 722d5ac70f0Sopenharmony_ci break; 723d5ac70f0Sopenharmony_ci case SND_TRY: 724d5ac70f0Sopenharmony_ci save = *params; 725d5ac70f0Sopenharmony_ci break; 726d5ac70f0Sopenharmony_ci case SND_TEST: 727d5ac70f0Sopenharmony_ci save = *params; 728d5ac70f0Sopenharmony_ci params = &save; 729d5ac70f0Sopenharmony_ci break; 730d5ac70f0Sopenharmony_ci default: 731d5ac70f0Sopenharmony_ci assert(0); 732d5ac70f0Sopenharmony_ci return -EINVAL; 733d5ac70f0Sopenharmony_ci } 734d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, var, val, dir); 735d5ac70f0Sopenharmony_ci if (err < 0) 736d5ac70f0Sopenharmony_ci goto _fail; 737d5ac70f0Sopenharmony_ci if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { 738d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 739d5ac70f0Sopenharmony_ci if (err < 0) 740d5ac70f0Sopenharmony_ci goto _fail; 741d5ac70f0Sopenharmony_ci } 742d5ac70f0Sopenharmony_ci return 0; 743d5ac70f0Sopenharmony_ci _fail: 744d5ac70f0Sopenharmony_ci if (mode == SND_TRY) 745d5ac70f0Sopenharmony_ci *params = save; 746d5ac70f0Sopenharmony_ci if (err < 0 && mode == SND_TRY) 747d5ac70f0Sopenharmony_ci dump_hw_params(params, "set", var, val, err); 748d5ac70f0Sopenharmony_ci return err; 749d5ac70f0Sopenharmony_ci} 750d5ac70f0Sopenharmony_ci 751d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t *params, 752d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, const snd_mask_t *val) 753d5ac70f0Sopenharmony_ci{ 754d5ac70f0Sopenharmony_ci int changed; 755d5ac70f0Sopenharmony_ci assert(hw_is_mask(var)); 756d5ac70f0Sopenharmony_ci changed = snd_mask_refine(hw_param_mask(params, var), val); 757d5ac70f0Sopenharmony_ci if (changed) { 758d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 759d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 760d5ac70f0Sopenharmony_ci } 761d5ac70f0Sopenharmony_ci return changed; 762d5ac70f0Sopenharmony_ci} 763d5ac70f0Sopenharmony_ci 764d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS remove from PAR all values 765d5ac70f0Sopenharmony_ci not contained in MASK. Reduce configuration space accordingly. 766d5ac70f0Sopenharmony_ci This function can be called only for SND_PCM_HW_PARAM_ACCESS, 767d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. 768d5ac70f0Sopenharmony_ci Return 0 on success or -EINVAL 769d5ac70f0Sopenharmony_ci if the configuration space is empty 770d5ac70f0Sopenharmony_ci*/ 771d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 772d5ac70f0Sopenharmony_ci snd_set_mode_t mode, 773d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, const snd_mask_t *val) 774d5ac70f0Sopenharmony_ci{ 775d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 776d5ac70f0Sopenharmony_ci int err; 777d5ac70f0Sopenharmony_ci switch (mode) { 778d5ac70f0Sopenharmony_ci case SND_CHANGE: 779d5ac70f0Sopenharmony_ci break; 780d5ac70f0Sopenharmony_ci case SND_TRY: 781d5ac70f0Sopenharmony_ci save = *params; 782d5ac70f0Sopenharmony_ci break; 783d5ac70f0Sopenharmony_ci case SND_TEST: 784d5ac70f0Sopenharmony_ci save = *params; 785d5ac70f0Sopenharmony_ci params = &save; 786d5ac70f0Sopenharmony_ci break; 787d5ac70f0Sopenharmony_ci default: 788d5ac70f0Sopenharmony_ci assert(0); 789d5ac70f0Sopenharmony_ci return -EINVAL; 790d5ac70f0Sopenharmony_ci } 791d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, var, val); 792d5ac70f0Sopenharmony_ci if (err < 0) 793d5ac70f0Sopenharmony_ci goto _fail; 794d5ac70f0Sopenharmony_ci if (mode != SND_TEST && params->rmask) { 795d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 796d5ac70f0Sopenharmony_ci if (err < 0) 797d5ac70f0Sopenharmony_ci goto _fail; 798d5ac70f0Sopenharmony_ci } 799d5ac70f0Sopenharmony_ci return 0; 800d5ac70f0Sopenharmony_ci _fail: 801d5ac70f0Sopenharmony_ci if (mode == SND_TRY) 802d5ac70f0Sopenharmony_ci *params = save; 803d5ac70f0Sopenharmony_ci return err; 804d5ac70f0Sopenharmony_ci} 805d5ac70f0Sopenharmony_ci 806d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS set PAR to the available value 807d5ac70f0Sopenharmony_ci nearest to VAL. Reduce configuration space accordingly. 808d5ac70f0Sopenharmony_ci This function cannot be called for SND_PCM_HW_PARAM_ACCESS, 809d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. 810d5ac70f0Sopenharmony_ci Return the value found. 811d5ac70f0Sopenharmony_ci */ 812d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 813d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 814d5ac70f0Sopenharmony_ci unsigned int *val, int *dir) 815d5ac70f0Sopenharmony_ci{ 816d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 817d5ac70f0Sopenharmony_ci int err; 818d5ac70f0Sopenharmony_ci unsigned int best = *val, saved_min; 819d5ac70f0Sopenharmony_ci int last = 0; 820d5ac70f0Sopenharmony_ci unsigned int min, max; 821d5ac70f0Sopenharmony_ci int mindir, maxdir; 822d5ac70f0Sopenharmony_ci int valdir = dir ? *dir : 0; 823d5ac70f0Sopenharmony_ci snd_interval_t *i; 824d5ac70f0Sopenharmony_ci /* FIXME */ 825d5ac70f0Sopenharmony_ci if (best > INT_MAX) 826d5ac70f0Sopenharmony_ci best = INT_MAX; 827d5ac70f0Sopenharmony_ci min = max = best; 828d5ac70f0Sopenharmony_ci mindir = maxdir = valdir; 829d5ac70f0Sopenharmony_ci if (maxdir > 0) 830d5ac70f0Sopenharmony_ci maxdir = 0; 831d5ac70f0Sopenharmony_ci else if (maxdir == 0) 832d5ac70f0Sopenharmony_ci maxdir = -1; 833d5ac70f0Sopenharmony_ci else { 834d5ac70f0Sopenharmony_ci maxdir = 1; 835d5ac70f0Sopenharmony_ci max--; 836d5ac70f0Sopenharmony_ci } 837d5ac70f0Sopenharmony_ci save = *params; 838d5ac70f0Sopenharmony_ci saved_min = min; 839d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir); 840d5ac70f0Sopenharmony_ci 841d5ac70f0Sopenharmony_ci i = hw_param_interval(params, var); 842d5ac70f0Sopenharmony_ci if (!snd_interval_empty(i) && snd_interval_single(i)) { 843d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_get_min(params, var, val, dir); 844d5ac70f0Sopenharmony_ci if (err < 0) 845d5ac70f0Sopenharmony_ci dump_hw_params(params, "set_near", var, *val, err); 846d5ac70f0Sopenharmony_ci return err; 847d5ac70f0Sopenharmony_ci } 848d5ac70f0Sopenharmony_ci 849d5ac70f0Sopenharmony_ci if (err >= 0) { 850d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t params1; 851d5ac70f0Sopenharmony_ci if (min == saved_min && mindir == valdir) 852d5ac70f0Sopenharmony_ci goto _end; 853d5ac70f0Sopenharmony_ci params1 = save; 854d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_max(pcm, ¶ms1, SND_CHANGE, var, &max, &maxdir); 855d5ac70f0Sopenharmony_ci if (err < 0) 856d5ac70f0Sopenharmony_ci goto _end; 857d5ac70f0Sopenharmony_ci if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { 858d5ac70f0Sopenharmony_ci *params = params1; 859d5ac70f0Sopenharmony_ci last = 1; 860d5ac70f0Sopenharmony_ci } 861d5ac70f0Sopenharmony_ci } else { 862d5ac70f0Sopenharmony_ci *params = save; 863d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir); 864d5ac70f0Sopenharmony_ci if (err < 0) { 865d5ac70f0Sopenharmony_ci dump_hw_params(params, "set_near", var, *val, err); 866d5ac70f0Sopenharmony_ci return err; 867d5ac70f0Sopenharmony_ci } 868d5ac70f0Sopenharmony_ci last = 1; 869d5ac70f0Sopenharmony_ci } 870d5ac70f0Sopenharmony_ci _end: 871d5ac70f0Sopenharmony_ci if (last) 872d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_last(pcm, params, var, val, dir); 873d5ac70f0Sopenharmony_ci else 874d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, var, val, dir); 875d5ac70f0Sopenharmony_ci if (err < 0) 876d5ac70f0Sopenharmony_ci dump_hw_params(params, "set_near", var, *val, err); 877d5ac70f0Sopenharmony_ci return err; 878d5ac70f0Sopenharmony_ci} 879d5ac70f0Sopenharmony_ci 880d5ac70f0Sopenharmony_ci#if 0 881d5ac70f0Sopenharmony_ci/* Inside configuration space defined by PARAMS set PAR to the available value 882d5ac70f0Sopenharmony_ci nearest to BEST after VAL (on equal difference values less than BEST are 883d5ac70f0Sopenharmony_ci returned first). 884d5ac70f0Sopenharmony_ci Reduce configuration space accordingly. 885d5ac70f0Sopenharmony_ci This function cannot be called for SND_PCM_HW_PARAM_ACCESS, 886d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. 887d5ac70f0Sopenharmony_ci Return the value found. 888d5ac70f0Sopenharmony_ci */ 889d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_set_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 890d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 891d5ac70f0Sopenharmony_ci unsigned int best, int bestdir, 892d5ac70f0Sopenharmony_ci unsigned int val, int *dir) 893d5ac70f0Sopenharmony_ci{ 894d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t save; 895d5ac70f0Sopenharmony_ci int v, err; 896d5ac70f0Sopenharmony_ci int last = 0; 897d5ac70f0Sopenharmony_ci int min, max; 898d5ac70f0Sopenharmony_ci int mindir, maxdir; 899d5ac70f0Sopenharmony_ci int diff, diffdir; 900d5ac70f0Sopenharmony_ci int valdir = dir ? *dir : 0; 901d5ac70f0Sopenharmony_ci /* FIXME */ 902d5ac70f0Sopenharmony_ci if (best > INT_MAX) 903d5ac70f0Sopenharmony_ci best = INT_MAX; 904d5ac70f0Sopenharmony_ci boundary_sub(val, valdir, best, bestdir, &diff, &diffdir); 905d5ac70f0Sopenharmony_ci if (diff < 0 || (diff == 0 && diffdir < 0)) { 906d5ac70f0Sopenharmony_ci min = best - diff; 907d5ac70f0Sopenharmony_ci mindir = bestdir - diffdir; 908d5ac70f0Sopenharmony_ci max = val; 909d5ac70f0Sopenharmony_ci maxdir = bestdir - 1; 910d5ac70f0Sopenharmony_ci } else { 911d5ac70f0Sopenharmony_ci min = val; 912d5ac70f0Sopenharmony_ci mindir = bestdir + 1; 913d5ac70f0Sopenharmony_ci max = best + diff; 914d5ac70f0Sopenharmony_ci maxdir = bestdir + diffdir + 1; 915d5ac70f0Sopenharmony_ci } 916d5ac70f0Sopenharmony_ci min += mindir / 2; 917d5ac70f0Sopenharmony_ci mindir %= 2; 918d5ac70f0Sopenharmony_ci max += maxdir / 2; 919d5ac70f0Sopenharmony_ci maxdir %= 2; 920d5ac70f0Sopenharmony_ci save = *params; 921d5ac70f0Sopenharmony_ci if (min >= 0 && 922d5ac70f0Sopenharmony_ci (err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir)) >= 0) { 923d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t params1; 924d5ac70f0Sopenharmony_ci if (max < 0) 925d5ac70f0Sopenharmony_ci goto _end; 926d5ac70f0Sopenharmony_ci params1 = save; 927d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_max(pcm, ¶ms1, SND_CHANGE, var, &max, &maxdir); 928d5ac70f0Sopenharmony_ci if (err < 0) 929d5ac70f0Sopenharmony_ci goto _end; 930d5ac70f0Sopenharmony_ci if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) { 931d5ac70f0Sopenharmony_ci *params = params1; 932d5ac70f0Sopenharmony_ci last = 1; 933d5ac70f0Sopenharmony_ci } 934d5ac70f0Sopenharmony_ci } else { 935d5ac70f0Sopenharmony_ci if (max < 0) 936d5ac70f0Sopenharmony_ci return -EINVAL; 937d5ac70f0Sopenharmony_ci *params = save; 938d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir); 939d5ac70f0Sopenharmony_ci if (err < 0) 940d5ac70f0Sopenharmony_ci return max; 941d5ac70f0Sopenharmony_ci last = 1; 942d5ac70f0Sopenharmony_ci } 943d5ac70f0Sopenharmony_ci _end: 944d5ac70f0Sopenharmony_ci if (last) 945d5ac70f0Sopenharmony_ci v = snd_pcm_hw_param_set_last(pcm, params, var, dir); 946d5ac70f0Sopenharmony_ci else 947d5ac70f0Sopenharmony_ci v = snd_pcm_hw_param_set_first(pcm, params, var, dir); 948d5ac70f0Sopenharmony_ci assert(v >= 0); 949d5ac70f0Sopenharmony_ci return v; 950d5ac70f0Sopenharmony_ci} 951d5ac70f0Sopenharmony_ci#endif 952d5ac70f0Sopenharmony_ci 953d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_param_set_near_minmax(snd_pcm_t *pcm, 954d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 955d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 956d5ac70f0Sopenharmony_ci unsigned int min, int *mindir, 957d5ac70f0Sopenharmony_ci unsigned int max, int *maxdir) 958d5ac70f0Sopenharmony_ci{ 959d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t tmp; 960d5ac70f0Sopenharmony_ci int err; 961d5ac70f0Sopenharmony_ci if (!boundary_lt(min, *mindir, max, *maxdir)) 962d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_set_near(pcm, params, var, &min, mindir); 963d5ac70f0Sopenharmony_ci tmp = *params; 964d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &min, mindir); 965d5ac70f0Sopenharmony_ci if (err < 0) 966d5ac70f0Sopenharmony_ci return err; 967d5ac70f0Sopenharmony_ci if (boundary_lt(min, *mindir, max, *maxdir)) { 968d5ac70f0Sopenharmony_ci tmp = *params; 969d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &max, maxdir); 970d5ac70f0Sopenharmony_ci } else { 971d5ac70f0Sopenharmony_ci max = min; 972d5ac70f0Sopenharmony_ci *maxdir = *mindir; 973d5ac70f0Sopenharmony_ci } 974d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_minmax(pcm, params, SND_CHANGE, var, &min, mindir, 975d5ac70f0Sopenharmony_ci &max, maxdir); 976d5ac70f0Sopenharmony_ci if (err < 0) 977d5ac70f0Sopenharmony_ci return err; 978d5ac70f0Sopenharmony_ci return 0; 979d5ac70f0Sopenharmony_ci} 980d5ac70f0Sopenharmony_ci 981d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_refine_near(snd_pcm_t *pcm, 982d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 983d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 984d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *src) 985d5ac70f0Sopenharmony_ci{ 986d5ac70f0Sopenharmony_ci unsigned int min, max; 987d5ac70f0Sopenharmony_ci int mindir, maxdir, err; 988d5ac70f0Sopenharmony_ci 989d5ac70f0Sopenharmony_ci if ((err = snd_pcm_hw_param_get_min(src, var, &min, &mindir)) < 0) 990d5ac70f0Sopenharmony_ci return err; 991d5ac70f0Sopenharmony_ci if ((err = snd_pcm_hw_param_get_max(src, var, &max, &maxdir)) < 0) 992d5ac70f0Sopenharmony_ci return err; 993d5ac70f0Sopenharmony_ci if ((err = snd_pcm_hw_param_set_near_minmax(pcm, params, var, 994d5ac70f0Sopenharmony_ci min, &mindir, max, &maxdir)) < 0) 995d5ac70f0Sopenharmony_ci return err; 996d5ac70f0Sopenharmony_ci return 0; 997d5ac70f0Sopenharmony_ci} 998d5ac70f0Sopenharmony_ci 999d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_refine_multiple(snd_pcm_t *pcm, 1000d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 1001d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1002d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *src) 1003d5ac70f0Sopenharmony_ci{ 1004d5ac70f0Sopenharmony_ci const snd_interval_t *it = hw_param_interval_c(src, var); 1005d5ac70f0Sopenharmony_ci const snd_interval_t *st = hw_param_interval_c(params, var); 1006d5ac70f0Sopenharmony_ci if (snd_interval_single(it)) { 1007d5ac70f0Sopenharmony_ci unsigned int best = snd_interval_min(it), cur, prev; 1008d5ac70f0Sopenharmony_ci cur = best; 1009d5ac70f0Sopenharmony_ci for (;;) { 1010d5ac70f0Sopenharmony_ci if (st->max < cur || (st->max == cur && st->openmax)) 1011d5ac70f0Sopenharmony_ci break; 1012d5ac70f0Sopenharmony_ci if (it->min <= cur && ! (it->min == cur && st->openmin)) { 1013d5ac70f0Sopenharmony_ci if (! snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0)) 1014d5ac70f0Sopenharmony_ci return 0; /* ok */ 1015d5ac70f0Sopenharmony_ci } 1016d5ac70f0Sopenharmony_ci prev = cur; 1017d5ac70f0Sopenharmony_ci cur += best; 1018d5ac70f0Sopenharmony_ci if (cur <= prev) 1019d5ac70f0Sopenharmony_ci break; 1020d5ac70f0Sopenharmony_ci } 1021d5ac70f0Sopenharmony_ci } 1022d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_refine_near(pcm, params, var, src); 1023d5ac70f0Sopenharmony_ci} 1024d5ac70f0Sopenharmony_ci 1025d5ac70f0Sopenharmony_ci/* ---- end of refinement functions ---- */ 1026d5ac70f0Sopenharmony_ci 1027d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params, 1028d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 1029d5ac70f0Sopenharmony_ci{ 1030d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) 1031d5ac70f0Sopenharmony_ci return snd_mask_empty(hw_param_mask_c(params, var)); 1032d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) 1033d5ac70f0Sopenharmony_ci return snd_interval_empty(hw_param_interval_c(params, var)); 1034d5ac70f0Sopenharmony_ci assert(0); 1035d5ac70f0Sopenharmony_ci return -EINVAL; 1036d5ac70f0Sopenharmony_ci} 1037d5ac70f0Sopenharmony_ci 1038d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params, 1039d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1040d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *params1) 1041d5ac70f0Sopenharmony_ci{ 1042d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) 1043d5ac70f0Sopenharmony_ci return snd_mask_always_eq(hw_param_mask_c(params, var), 1044d5ac70f0Sopenharmony_ci hw_param_mask_c(params1, var)); 1045d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) 1046d5ac70f0Sopenharmony_ci return snd_interval_always_eq(hw_param_interval_c(params, var), 1047d5ac70f0Sopenharmony_ci hw_param_interval_c(params1, var)); 1048d5ac70f0Sopenharmony_ci assert(0); 1049d5ac70f0Sopenharmony_ci return -EINVAL; 1050d5ac70f0Sopenharmony_ci} 1051d5ac70f0Sopenharmony_ci 1052d5ac70f0Sopenharmony_ciint snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params, 1053d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1054d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *params1) 1055d5ac70f0Sopenharmony_ci{ 1056d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) 1057d5ac70f0Sopenharmony_ci return snd_mask_never_eq(hw_param_mask_c(params, var), 1058d5ac70f0Sopenharmony_ci hw_param_mask_c(params1, var)); 1059d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) 1060d5ac70f0Sopenharmony_ci return snd_interval_never_eq(hw_param_interval_c(params, var), 1061d5ac70f0Sopenharmony_ci hw_param_interval_c(params1, var)); 1062d5ac70f0Sopenharmony_ci assert(0); 1063d5ac70f0Sopenharmony_ci return -EINVAL; 1064d5ac70f0Sopenharmony_ci} 1065d5ac70f0Sopenharmony_ci 1066d5ac70f0Sopenharmony_ci#if 0 1067d5ac70f0Sopenharmony_ci#define CHOOSE_DEBUG 1068d5ac70f0Sopenharmony_ci#endif 1069d5ac70f0Sopenharmony_ci 1070d5ac70f0Sopenharmony_ci/* Choose one configuration from configuration space defined by PARAMS 1071d5ac70f0Sopenharmony_ci The configuration chosen is that obtained fixing in this order: 1072d5ac70f0Sopenharmony_ci first access 1073d5ac70f0Sopenharmony_ci first format 1074d5ac70f0Sopenharmony_ci first subformat 1075d5ac70f0Sopenharmony_ci min channels 1076d5ac70f0Sopenharmony_ci min rate 1077d5ac70f0Sopenharmony_ci min period time 1078d5ac70f0Sopenharmony_ci max buffer size 1079d5ac70f0Sopenharmony_ci min tick time 1080d5ac70f0Sopenharmony_ci*/ 1081d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 1082d5ac70f0Sopenharmony_ci{ 1083d5ac70f0Sopenharmony_ci int err; 1084d5ac70f0Sopenharmony_ci#ifdef CHOOSE_DEBUG 1085d5ac70f0Sopenharmony_ci snd_output_t *log; 1086d5ac70f0Sopenharmony_ci snd_output_stdio_attach(&log, stderr, 0); 1087d5ac70f0Sopenharmony_ci snd_output_printf(log, "CHOOSE called:\n"); 1088d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 1089d5ac70f0Sopenharmony_ci#endif 1090d5ac70f0Sopenharmony_ci 1091d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0); 1092d5ac70f0Sopenharmony_ci if (err < 0) 1093d5ac70f0Sopenharmony_ci return err; 1094d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL, 0); 1095d5ac70f0Sopenharmony_ci if (err < 0) 1096d5ac70f0Sopenharmony_ci return err; 1097d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL, 0); 1098d5ac70f0Sopenharmony_ci if (err < 0) 1099d5ac70f0Sopenharmony_ci return err; 1100d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL, 0); 1101d5ac70f0Sopenharmony_ci if (err < 0) 1102d5ac70f0Sopenharmony_ci return err; 1103d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, NULL, 0); 1104d5ac70f0Sopenharmony_ci if (err < 0) 1105d5ac70f0Sopenharmony_ci return err; 1106d5ac70f0Sopenharmony_ci if (pcm->minperiodtime > 0) { 1107d5ac70f0Sopenharmony_ci unsigned int min, max; 1108d5ac70f0Sopenharmony_ci int dir = 1; 1109d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir); 1110d5ac70f0Sopenharmony_ci if (err >= 0) 1111d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_TIME, &max, &dir); 1112d5ac70f0Sopenharmony_ci if (err >= 0 && (long)min < pcm->minperiodtime && 1113d5ac70f0Sopenharmony_ci (long)max > pcm->minperiodtime) { 1114d5ac70f0Sopenharmony_ci min = pcm->minperiodtime; dir = 1; 1115d5ac70f0Sopenharmony_ci snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir); 1116d5ac70f0Sopenharmony_ci } 1117d5ac70f0Sopenharmony_ci } 1118d5ac70f0Sopenharmony_ci if (pcm->compat) { 1119d5ac70f0Sopenharmony_ci /* old mode */ 1120d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0); 1121d5ac70f0Sopenharmony_ci if (err < 0) 1122d5ac70f0Sopenharmony_ci return err; 1123d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0); 1124d5ac70f0Sopenharmony_ci if (err < 0) 1125d5ac70f0Sopenharmony_ci return err; 1126d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0); 1127d5ac70f0Sopenharmony_ci if (err < 0) 1128d5ac70f0Sopenharmony_ci return err; 1129d5ac70f0Sopenharmony_ci } else { 1130d5ac70f0Sopenharmony_ci /* determine buffer size first */ 1131d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0); 1132d5ac70f0Sopenharmony_ci if (err < 0) 1133d5ac70f0Sopenharmony_ci return err; 1134d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0); 1135d5ac70f0Sopenharmony_ci if (err < 0) 1136d5ac70f0Sopenharmony_ci return err; 1137d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0); 1138d5ac70f0Sopenharmony_ci if (err < 0) 1139d5ac70f0Sopenharmony_ci return err; 1140d5ac70f0Sopenharmony_ci } 1141d5ac70f0Sopenharmony_ci err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0); 1142d5ac70f0Sopenharmony_ci if (err < 0) 1143d5ac70f0Sopenharmony_ci return err; 1144d5ac70f0Sopenharmony_ci#ifdef CHOOSE_DEBUG 1145d5ac70f0Sopenharmony_ci snd_output_printf(log, "choose done\n"); 1146d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 1147d5ac70f0Sopenharmony_ci snd_output_close(log); 1148d5ac70f0Sopenharmony_ci#endif 1149d5ac70f0Sopenharmony_ci return 0; 1150d5ac70f0Sopenharmony_ci} 1151d5ac70f0Sopenharmony_ci 1152d5ac70f0Sopenharmony_ci#if 0 1153d5ac70f0Sopenharmony_cistatic unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params, 1154d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var) 1155d5ac70f0Sopenharmony_ci{ 1156d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 1157d5ac70f0Sopenharmony_ci const snd_mask_t *mask = hw_param_mask_c(params, var); 1158d5ac70f0Sopenharmony_ci return snd_mask_count(mask); 1159d5ac70f0Sopenharmony_ci } 1160d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) { 1161d5ac70f0Sopenharmony_ci const snd_interval_t *i = hw_param_interval_c(params, var); 1162d5ac70f0Sopenharmony_ci return snd_interval_max(i) - snd_interval_min(i) + 1; 1163d5ac70f0Sopenharmony_ci } 1164d5ac70f0Sopenharmony_ci assert(0); 1165d5ac70f0Sopenharmony_ci return 0; 1166d5ac70f0Sopenharmony_ci} 1167d5ac70f0Sopenharmony_ci#endif 1168d5ac70f0Sopenharmony_ci 1169d5ac70f0Sopenharmony_ciint _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, 1170d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1171d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *src) 1172d5ac70f0Sopenharmony_ci{ 1173d5ac70f0Sopenharmony_ci int changed = 0; 1174d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 1175d5ac70f0Sopenharmony_ci snd_mask_t *d = hw_param_mask(params, var); 1176d5ac70f0Sopenharmony_ci const snd_mask_t *s = hw_param_mask_c(src, var); 1177d5ac70f0Sopenharmony_ci changed = snd_mask_refine(d, s); 1178d5ac70f0Sopenharmony_ci } else if (hw_is_interval(var)) { 1179d5ac70f0Sopenharmony_ci snd_interval_t *d = hw_param_interval(params, var); 1180d5ac70f0Sopenharmony_ci const snd_interval_t *s = hw_param_interval_c(src, var); 1181d5ac70f0Sopenharmony_ci changed = snd_interval_refine(d, s); 1182d5ac70f0Sopenharmony_ci } else 1183d5ac70f0Sopenharmony_ci return 0; /* NOP / reserved */ 1184d5ac70f0Sopenharmony_ci if (changed) { 1185d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 1186d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 1187d5ac70f0Sopenharmony_ci } 1188d5ac70f0Sopenharmony_ci return changed; 1189d5ac70f0Sopenharmony_ci} 1190d5ac70f0Sopenharmony_ci 1191d5ac70f0Sopenharmony_ci#if 0 1192d5ac70f0Sopenharmony_cistatic void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, 1193d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *src) 1194d5ac70f0Sopenharmony_ci{ 1195d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 1196d5ac70f0Sopenharmony_ci snd_mask_t *d = hw_param_mask(params, var); 1197d5ac70f0Sopenharmony_ci const snd_mask_t *s = hw_param_mask_c(src, var); 1198d5ac70f0Sopenharmony_ci snd_mask_copy(d, s); 1199d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 1200d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 1201d5ac70f0Sopenharmony_ci return; 1202d5ac70f0Sopenharmony_ci } 1203d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) { 1204d5ac70f0Sopenharmony_ci snd_interval_t *d = hw_param_interval(params, var); 1205d5ac70f0Sopenharmony_ci const snd_interval_t *s = hw_param_interval_c(src, var); 1206d5ac70f0Sopenharmony_ci snd_interval_copy(d, s); 1207d5ac70f0Sopenharmony_ci params->cmask |= 1 << var; 1208d5ac70f0Sopenharmony_ci params->rmask |= 1 << var; 1209d5ac70f0Sopenharmony_ci return; 1210d5ac70f0Sopenharmony_ci } 1211d5ac70f0Sopenharmony_ci assert(0); 1212d5ac70f0Sopenharmony_ci} 1213d5ac70f0Sopenharmony_ci#endif 1214d5ac70f0Sopenharmony_ci 1215d5ac70f0Sopenharmony_civoid snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params, 1216d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, snd_output_t *out) 1217d5ac70f0Sopenharmony_ci{ 1218d5ac70f0Sopenharmony_ci if (hw_is_mask(var)) { 1219d5ac70f0Sopenharmony_ci const snd_mask_t *mask = hw_param_mask_c(params, var); 1220d5ac70f0Sopenharmony_ci if (snd_mask_empty(mask)) 1221d5ac70f0Sopenharmony_ci snd_output_puts(out, " NONE"); 1222d5ac70f0Sopenharmony_ci else if (snd_mask_full(mask)) 1223d5ac70f0Sopenharmony_ci snd_output_puts(out, " ALL"); 1224d5ac70f0Sopenharmony_ci else { 1225d5ac70f0Sopenharmony_ci unsigned int k; 1226d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_MASK_MAX; ++k) { 1227d5ac70f0Sopenharmony_ci if (snd_mask_test(mask, k)) { 1228d5ac70f0Sopenharmony_ci const char *s; 1229d5ac70f0Sopenharmony_ci switch (var) { 1230d5ac70f0Sopenharmony_ci case SND_PCM_HW_PARAM_ACCESS: 1231d5ac70f0Sopenharmony_ci s = snd_pcm_access_name(k); 1232d5ac70f0Sopenharmony_ci break; 1233d5ac70f0Sopenharmony_ci case SND_PCM_HW_PARAM_FORMAT: 1234d5ac70f0Sopenharmony_ci s = snd_pcm_format_name(k); 1235d5ac70f0Sopenharmony_ci break; 1236d5ac70f0Sopenharmony_ci case SND_PCM_HW_PARAM_SUBFORMAT: 1237d5ac70f0Sopenharmony_ci s = snd_pcm_subformat_name(k); 1238d5ac70f0Sopenharmony_ci break; 1239d5ac70f0Sopenharmony_ci default: 1240d5ac70f0Sopenharmony_ci assert(0); 1241d5ac70f0Sopenharmony_ci s = NULL; 1242d5ac70f0Sopenharmony_ci } 1243d5ac70f0Sopenharmony_ci if (s) { 1244d5ac70f0Sopenharmony_ci snd_output_putc(out, ' '); 1245d5ac70f0Sopenharmony_ci snd_output_puts(out, s); 1246d5ac70f0Sopenharmony_ci } 1247d5ac70f0Sopenharmony_ci } 1248d5ac70f0Sopenharmony_ci } 1249d5ac70f0Sopenharmony_ci } 1250d5ac70f0Sopenharmony_ci return; 1251d5ac70f0Sopenharmony_ci } 1252d5ac70f0Sopenharmony_ci if (hw_is_interval(var)) { 1253d5ac70f0Sopenharmony_ci snd_interval_print(hw_param_interval_c(params, var), out); 1254d5ac70f0Sopenharmony_ci return; 1255d5ac70f0Sopenharmony_ci } 1256d5ac70f0Sopenharmony_ci assert(0); 1257d5ac70f0Sopenharmony_ci} 1258d5ac70f0Sopenharmony_ci 1259d5ac70f0Sopenharmony_ci#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v 1260d5ac70f0Sopenharmony_ci 1261d5ac70f0Sopenharmony_cistatic const char *const snd_pcm_hw_param_names[] = { 1262d5ac70f0Sopenharmony_ci HW_PARAM(ACCESS), 1263d5ac70f0Sopenharmony_ci HW_PARAM(FORMAT), 1264d5ac70f0Sopenharmony_ci HW_PARAM(SUBFORMAT), 1265d5ac70f0Sopenharmony_ci HW_PARAM(SAMPLE_BITS), 1266d5ac70f0Sopenharmony_ci HW_PARAM(FRAME_BITS), 1267d5ac70f0Sopenharmony_ci HW_PARAM(CHANNELS), 1268d5ac70f0Sopenharmony_ci HW_PARAM(RATE), 1269d5ac70f0Sopenharmony_ci HW_PARAM(PERIOD_TIME), 1270d5ac70f0Sopenharmony_ci HW_PARAM(PERIOD_SIZE), 1271d5ac70f0Sopenharmony_ci HW_PARAM(PERIOD_BYTES), 1272d5ac70f0Sopenharmony_ci HW_PARAM(PERIODS), 1273d5ac70f0Sopenharmony_ci HW_PARAM(BUFFER_TIME), 1274d5ac70f0Sopenharmony_ci HW_PARAM(BUFFER_SIZE), 1275d5ac70f0Sopenharmony_ci HW_PARAM(BUFFER_BYTES), 1276d5ac70f0Sopenharmony_ci HW_PARAM(TICK_TIME), 1277d5ac70f0Sopenharmony_ci}; 1278d5ac70f0Sopenharmony_ci 1279d5ac70f0Sopenharmony_ciconst char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param) 1280d5ac70f0Sopenharmony_ci{ 1281d5ac70f0Sopenharmony_ci assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL); 1282d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_names[param]; 1283d5ac70f0Sopenharmony_ci} 1284d5ac70f0Sopenharmony_ci 1285d5ac70f0Sopenharmony_ci#if 0 1286d5ac70f0Sopenharmony_ci/* Strategies */ 1287d5ac70f0Sopenharmony_ci 1288d5ac70f0Sopenharmony_cistruct _snd_pcm_hw_strategy { 1289d5ac70f0Sopenharmony_ci unsigned int badness_min, badness_max; 1290d5ac70f0Sopenharmony_ci int (*choose_param)(const snd_pcm_hw_params_t *params, 1291d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1292d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy); 1293d5ac70f0Sopenharmony_ci int (*next_value)(snd_pcm_hw_params_t *params, 1294d5ac70f0Sopenharmony_ci unsigned int param, 1295d5ac70f0Sopenharmony_ci int value, int *dir, 1296d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1297d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy); 1298d5ac70f0Sopenharmony_ci int (*min_badness)(const snd_pcm_hw_params_t *params, 1299d5ac70f0Sopenharmony_ci unsigned int max_badness, 1300d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1301d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy); 1302d5ac70f0Sopenharmony_ci void *private_data; 1303d5ac70f0Sopenharmony_ci void (*free)(snd_pcm_hw_strategy_t *strategy); 1304d5ac70f0Sopenharmony_ci}; 1305d5ac70f0Sopenharmony_ci 1306d5ac70f0Sopenharmony_ci/* Independent badness */ 1307d5ac70f0Sopenharmony_citypedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t; 1308d5ac70f0Sopenharmony_ci 1309d5ac70f0Sopenharmony_cistruct _snd_pcm_hw_strategy_simple { 1310d5ac70f0Sopenharmony_ci int valid; 1311d5ac70f0Sopenharmony_ci unsigned int order; 1312d5ac70f0Sopenharmony_ci int (*next_value)(snd_pcm_hw_params_t *params, 1313d5ac70f0Sopenharmony_ci unsigned int param, 1314d5ac70f0Sopenharmony_ci int value, int *dir, 1315d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1316d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *par); 1317d5ac70f0Sopenharmony_ci unsigned int (*min_badness)(const snd_pcm_hw_params_t *params, 1318d5ac70f0Sopenharmony_ci unsigned int param, 1319d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1320d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *par); 1321d5ac70f0Sopenharmony_ci void *private_data; 1322d5ac70f0Sopenharmony_ci void (*free)(snd_pcm_hw_strategy_simple_t *strategy); 1323d5ac70f0Sopenharmony_ci}; 1324d5ac70f0Sopenharmony_ci 1325d5ac70f0Sopenharmony_citypedef struct _snd_pcm_hw_strategy_simple_near { 1326d5ac70f0Sopenharmony_ci int best; 1327d5ac70f0Sopenharmony_ci unsigned int mul; 1328d5ac70f0Sopenharmony_ci} snd_pcm_hw_strategy_simple_near_t; 1329d5ac70f0Sopenharmony_ci 1330d5ac70f0Sopenharmony_citypedef struct _snd_pcm_hw_strategy_simple_choices { 1331d5ac70f0Sopenharmony_ci unsigned int count; 1332d5ac70f0Sopenharmony_ci /* choices need to be sorted on ascending badness */ 1333d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_choices_list_t *choices; 1334d5ac70f0Sopenharmony_ci} snd_pcm_hw_strategy_simple_choices_t; 1335d5ac70f0Sopenharmony_ci 1336d5ac70f0Sopenharmony_ciint snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 1337d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy, 1338d5ac70f0Sopenharmony_ci unsigned int badness_min, 1339d5ac70f0Sopenharmony_ci unsigned int badness_max) 1340d5ac70f0Sopenharmony_ci{ 1341d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t best_params; 1342d5ac70f0Sopenharmony_ci int var; 1343d5ac70f0Sopenharmony_ci int value, dir; 1344d5ac70f0Sopenharmony_ci unsigned int best_badness; 1345d5ac70f0Sopenharmony_ci int badness = strategy->min_badness(params, badness_max, pcm, strategy); 1346d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t params1; 1347d5ac70f0Sopenharmony_ci#if 0 1348d5ac70f0Sopenharmony_ci printf("\nBadness: %d\n", badness); 1349d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, stdout); 1350d5ac70f0Sopenharmony_ci#endif 1351d5ac70f0Sopenharmony_ci if (badness < 0) 1352d5ac70f0Sopenharmony_ci return badness; 1353d5ac70f0Sopenharmony_ci if ((unsigned int)badness > badness_min) 1354d5ac70f0Sopenharmony_ci badness_min = badness_min; 1355d5ac70f0Sopenharmony_ci var = strategy->choose_param(params, pcm, strategy); 1356d5ac70f0Sopenharmony_ci if (var < 0) 1357d5ac70f0Sopenharmony_ci return badness; 1358d5ac70f0Sopenharmony_ci best_badness = UINT_MAX; 1359d5ac70f0Sopenharmony_ci value = -1; 1360d5ac70f0Sopenharmony_ci while (1) { 1361d5ac70f0Sopenharmony_ci params1 = *params; 1362d5ac70f0Sopenharmony_ci value = strategy->next_value(¶ms1, var, value, &dir, pcm, strategy); 1363d5ac70f0Sopenharmony_ci if (value < 0) 1364d5ac70f0Sopenharmony_ci break; 1365d5ac70f0Sopenharmony_ci badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, strategy, badness_min, badness_max); 1366d5ac70f0Sopenharmony_ci if (badness >= 0) { 1367d5ac70f0Sopenharmony_ci if ((unsigned int) badness <= badness_min) { 1368d5ac70f0Sopenharmony_ci *params = params1; 1369d5ac70f0Sopenharmony_ci return badness; 1370d5ac70f0Sopenharmony_ci } 1371d5ac70f0Sopenharmony_ci best_badness = badness; 1372d5ac70f0Sopenharmony_ci best_params = params1; 1373d5ac70f0Sopenharmony_ci badness_max = badness - 1; 1374d5ac70f0Sopenharmony_ci } 1375d5ac70f0Sopenharmony_ci } 1376d5ac70f0Sopenharmony_ci if (best_badness == UINT_MAX) { 1377d5ac70f0Sopenharmony_ci return -EINVAL; 1378d5ac70f0Sopenharmony_ci } 1379d5ac70f0Sopenharmony_ci *params = best_params; 1380d5ac70f0Sopenharmony_ci return best_badness; 1381d5ac70f0Sopenharmony_ci} 1382d5ac70f0Sopenharmony_ci 1383d5ac70f0Sopenharmony_civoid snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy) 1384d5ac70f0Sopenharmony_ci{ 1385d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; 1386d5ac70f0Sopenharmony_ci int k; 1387d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) { 1388d5ac70f0Sopenharmony_ci if (pars[k].valid && pars[k].free) 1389d5ac70f0Sopenharmony_ci pars[k].free(&pars[k]); 1390d5ac70f0Sopenharmony_ci } 1391d5ac70f0Sopenharmony_ci free(pars); 1392d5ac70f0Sopenharmony_ci} 1393d5ac70f0Sopenharmony_ci 1394d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params, 1395d5ac70f0Sopenharmony_ci snd_pcm_t *pcm ATTRIBUTE_UNUSED, 1396d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy) 1397d5ac70f0Sopenharmony_ci{ 1398d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var; 1399d5ac70f0Sopenharmony_ci int best_var = -1; 1400d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; 1401d5ac70f0Sopenharmony_ci unsigned int min_choices = UINT_MAX; 1402d5ac70f0Sopenharmony_ci unsigned int min_order = UINT_MAX; 1403d5ac70f0Sopenharmony_ci for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) { 1404d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *p = &pars[var]; 1405d5ac70f0Sopenharmony_ci unsigned int choices; 1406d5ac70f0Sopenharmony_ci if (!p->valid) 1407d5ac70f0Sopenharmony_ci continue; 1408d5ac70f0Sopenharmony_ci choices = snd_pcm_hw_param_count(params, var); 1409d5ac70f0Sopenharmony_ci if (choices == 1) 1410d5ac70f0Sopenharmony_ci continue; 1411d5ac70f0Sopenharmony_ci assert(choices != 0); 1412d5ac70f0Sopenharmony_ci if (p->order < min_order || 1413d5ac70f0Sopenharmony_ci (p->order == min_order && 1414d5ac70f0Sopenharmony_ci choices < min_choices)) { 1415d5ac70f0Sopenharmony_ci min_order = p->order; 1416d5ac70f0Sopenharmony_ci min_choices = choices; 1417d5ac70f0Sopenharmony_ci best_var = var; 1418d5ac70f0Sopenharmony_ci } 1419d5ac70f0Sopenharmony_ci } 1420d5ac70f0Sopenharmony_ci return best_var; 1421d5ac70f0Sopenharmony_ci} 1422d5ac70f0Sopenharmony_ci 1423d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_next_value(snd_pcm_hw_params_t *params, 1424d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1425d5ac70f0Sopenharmony_ci int value, int *dir, 1426d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1427d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy) 1428d5ac70f0Sopenharmony_ci{ 1429d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; 1430d5ac70f0Sopenharmony_ci assert(pars[var].valid); 1431d5ac70f0Sopenharmony_ci return pars[var].next_value(params, var, value, dir, pcm, &pars[var]); 1432d5ac70f0Sopenharmony_ci} 1433d5ac70f0Sopenharmony_ci 1434d5ac70f0Sopenharmony_ci 1435d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params, 1436d5ac70f0Sopenharmony_ci unsigned int max_badness, 1437d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1438d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_t *strategy) 1439d5ac70f0Sopenharmony_ci{ 1440d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var; 1441d5ac70f0Sopenharmony_ci unsigned int badness = 0; 1442d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; 1443d5ac70f0Sopenharmony_ci for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) { 1444d5ac70f0Sopenharmony_ci unsigned int b; 1445d5ac70f0Sopenharmony_ci if (!pars[var].valid) 1446d5ac70f0Sopenharmony_ci continue; 1447d5ac70f0Sopenharmony_ci b = pars[var].min_badness(params, var, pcm, &pars[var]); 1448d5ac70f0Sopenharmony_ci if (b > max_badness || max_badness - b < badness) 1449d5ac70f0Sopenharmony_ci return -E2BIG; 1450d5ac70f0Sopenharmony_ci badness += b; 1451d5ac70f0Sopenharmony_ci } 1452d5ac70f0Sopenharmony_ci return badness; 1453d5ac70f0Sopenharmony_ci} 1454d5ac70f0Sopenharmony_ci 1455d5ac70f0Sopenharmony_ci 1456d5ac70f0Sopenharmony_civoid snd_pcm_hw_strategy_simple_near_free(snd_pcm_hw_strategy_simple_t *par) 1457d5ac70f0Sopenharmony_ci{ 1458d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_near_t *p = par->private_data; 1459d5ac70f0Sopenharmony_ci free(p); 1460d5ac70f0Sopenharmony_ci} 1461d5ac70f0Sopenharmony_ci 1462d5ac70f0Sopenharmony_ciunsigned int snd_pcm_hw_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params, 1463d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1464d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1465d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *par) 1466d5ac70f0Sopenharmony_ci{ 1467d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_near_t *p = par->private_data; 1468d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t params1 = *params; 1469d5ac70f0Sopenharmony_ci int value = snd_pcm_hw_param_set_near(pcm, ¶ms1, var, p->best, 0); 1470d5ac70f0Sopenharmony_ci int diff; 1471d5ac70f0Sopenharmony_ci assert(value >= 0); 1472d5ac70f0Sopenharmony_ci diff = p->best - value; 1473d5ac70f0Sopenharmony_ci if (diff < 0) 1474d5ac70f0Sopenharmony_ci diff = -diff; 1475d5ac70f0Sopenharmony_ci return diff * p->mul; 1476d5ac70f0Sopenharmony_ci} 1477d5ac70f0Sopenharmony_ci 1478d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_near_next_value(snd_pcm_hw_params_t *params, 1479d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1480d5ac70f0Sopenharmony_ci int value, int *dir, 1481d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1482d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *par) 1483d5ac70f0Sopenharmony_ci{ 1484d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_near_t *p = par->private_data; 1485d5ac70f0Sopenharmony_ci if (value < 0) { 1486d5ac70f0Sopenharmony_ci *dir = 0; 1487d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_set_near(pcm, params, var, p->best, dir); 1488d5ac70f0Sopenharmony_ci } else 1489d5ac70f0Sopenharmony_ci return snd_pcm_hw_param_set_next(pcm, params, var, p->best, 0, value, dir); 1490d5ac70f0Sopenharmony_ci} 1491d5ac70f0Sopenharmony_ci 1492d5ac70f0Sopenharmony_civoid snd_pcm_hw_strategy_simple_choices_free(snd_pcm_hw_strategy_simple_t *par) 1493d5ac70f0Sopenharmony_ci{ 1494d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_choices_t *p = par->private_data; 1495d5ac70f0Sopenharmony_ci// free(p->choices); 1496d5ac70f0Sopenharmony_ci free(p); 1497d5ac70f0Sopenharmony_ci} 1498d5ac70f0Sopenharmony_ci 1499d5ac70f0Sopenharmony_ciunsigned int snd_pcm_hw_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params, 1500d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1501d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1502d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *par) 1503d5ac70f0Sopenharmony_ci{ 1504d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data; 1505d5ac70f0Sopenharmony_ci unsigned int k; 1506d5ac70f0Sopenharmony_ci for (k = 0; k < p->count; ++k) { 1507d5ac70f0Sopenharmony_ci if (snd_pcm_hw_param_set(pcm, (snd_pcm_hw_params_t *) params, SND_TEST, var, p->choices[k].value, 0)) 1508d5ac70f0Sopenharmony_ci return p->choices[k].badness; 1509d5ac70f0Sopenharmony_ci } 1510d5ac70f0Sopenharmony_ci assert(0); 1511d5ac70f0Sopenharmony_ci return UINT_MAX; 1512d5ac70f0Sopenharmony_ci} 1513d5ac70f0Sopenharmony_ci 1514d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params, 1515d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1516d5ac70f0Sopenharmony_ci int value, int *dir, 1517d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 1518d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_t *par) 1519d5ac70f0Sopenharmony_ci{ 1520d5ac70f0Sopenharmony_ci const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data; 1521d5ac70f0Sopenharmony_ci unsigned int k = 0; 1522d5ac70f0Sopenharmony_ci if (value >= 0) { 1523d5ac70f0Sopenharmony_ci for (; k < p->count; ++k) { 1524d5ac70f0Sopenharmony_ci if (p->choices[k].value == (unsigned int) value) { 1525d5ac70f0Sopenharmony_ci k++; 1526d5ac70f0Sopenharmony_ci break; 1527d5ac70f0Sopenharmony_ci } 1528d5ac70f0Sopenharmony_ci } 1529d5ac70f0Sopenharmony_ci } 1530d5ac70f0Sopenharmony_ci for (; k < p->count; ++k) { 1531d5ac70f0Sopenharmony_ci unsigned int v = p->choices[k].value; 1532d5ac70f0Sopenharmony_ci int err = snd_pcm_hw_param_set(pcm, params, SND_TRY, var, v, 0); 1533d5ac70f0Sopenharmony_ci if (err < 0) 1534d5ac70f0Sopenharmony_ci continue; 1535d5ac70f0Sopenharmony_ci *dir = 0; 1536d5ac70f0Sopenharmony_ci return v; 1537d5ac70f0Sopenharmony_ci } 1538d5ac70f0Sopenharmony_ci return -1; 1539d5ac70f0Sopenharmony_ci} 1540d5ac70f0Sopenharmony_ci 1541d5ac70f0Sopenharmony_civoid snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy) 1542d5ac70f0Sopenharmony_ci{ 1543d5ac70f0Sopenharmony_ci if (strategy->free) 1544d5ac70f0Sopenharmony_ci strategy->free(strategy); 1545d5ac70f0Sopenharmony_ci free(strategy); 1546d5ac70f0Sopenharmony_ci} 1547d5ac70f0Sopenharmony_ci 1548d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp, 1549d5ac70f0Sopenharmony_ci unsigned int badness_min, 1550d5ac70f0Sopenharmony_ci unsigned int badness_max) 1551d5ac70f0Sopenharmony_ci{ 1552d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_t *data; 1553d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_t *s; 1554d5ac70f0Sopenharmony_ci assert(strategyp); 1555d5ac70f0Sopenharmony_ci data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data)); 1556d5ac70f0Sopenharmony_ci if (!data) 1557d5ac70f0Sopenharmony_ci return -ENOMEM; 1558d5ac70f0Sopenharmony_ci s = calloc(1, sizeof(*s)); 1559d5ac70f0Sopenharmony_ci if (!s) { 1560d5ac70f0Sopenharmony_ci free(data); 1561d5ac70f0Sopenharmony_ci return -ENOMEM; 1562d5ac70f0Sopenharmony_ci } 1563d5ac70f0Sopenharmony_ci s->choose_param = snd_pcm_hw_strategy_simple_choose_param; 1564d5ac70f0Sopenharmony_ci s->next_value = snd_pcm_hw_strategy_simple_next_value; 1565d5ac70f0Sopenharmony_ci s->min_badness = snd_pcm_hw_strategy_simple_min_badness; 1566d5ac70f0Sopenharmony_ci s->badness_min = badness_min; 1567d5ac70f0Sopenharmony_ci s->badness_max = badness_max; 1568d5ac70f0Sopenharmony_ci s->private_data = data; 1569d5ac70f0Sopenharmony_ci s->free = snd_pcm_hw_strategy_simple_free; 1570d5ac70f0Sopenharmony_ci *strategyp = s; 1571d5ac70f0Sopenharmony_ci return 0; 1572d5ac70f0Sopenharmony_ci} 1573d5ac70f0Sopenharmony_ci 1574d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy, 1575d5ac70f0Sopenharmony_ci int order, 1576d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1577d5ac70f0Sopenharmony_ci unsigned int best, 1578d5ac70f0Sopenharmony_ci unsigned int mul) 1579d5ac70f0Sopenharmony_ci{ 1580d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_t *s = strategy->private_data; 1581d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_near_t *data; 1582d5ac70f0Sopenharmony_ci assert(strategy); 1583d5ac70f0Sopenharmony_ci assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL); 1584d5ac70f0Sopenharmony_ci assert(!s->valid); 1585d5ac70f0Sopenharmony_ci data = calloc(1, sizeof(*data)); 1586d5ac70f0Sopenharmony_ci if (!data) 1587d5ac70f0Sopenharmony_ci return -ENOMEM; 1588d5ac70f0Sopenharmony_ci data->best = best; 1589d5ac70f0Sopenharmony_ci data->mul = mul; 1590d5ac70f0Sopenharmony_ci s += var; 1591d5ac70f0Sopenharmony_ci s->order = order; 1592d5ac70f0Sopenharmony_ci s->valid = 1; 1593d5ac70f0Sopenharmony_ci s->next_value = snd_pcm_hw_strategy_simple_near_next_value; 1594d5ac70f0Sopenharmony_ci s->min_badness = snd_pcm_hw_strategy_simple_near_min_badness; 1595d5ac70f0Sopenharmony_ci s->private_data = data; 1596d5ac70f0Sopenharmony_ci s->free = snd_pcm_hw_strategy_simple_near_free; 1597d5ac70f0Sopenharmony_ci return 0; 1598d5ac70f0Sopenharmony_ci} 1599d5ac70f0Sopenharmony_ci 1600d5ac70f0Sopenharmony_ciint snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, 1601d5ac70f0Sopenharmony_ci int order, 1602d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var, 1603d5ac70f0Sopenharmony_ci unsigned int count, 1604d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_choices_list_t *choices) 1605d5ac70f0Sopenharmony_ci{ 1606d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_t *s = strategy->private_data; 1607d5ac70f0Sopenharmony_ci snd_pcm_hw_strategy_simple_choices_t *data; 1608d5ac70f0Sopenharmony_ci assert(strategy); 1609d5ac70f0Sopenharmony_ci assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL); 1610d5ac70f0Sopenharmony_ci assert(!s->valid); 1611d5ac70f0Sopenharmony_ci data = calloc(1, sizeof(*data)); 1612d5ac70f0Sopenharmony_ci if (!data) 1613d5ac70f0Sopenharmony_ci return -ENOMEM; 1614d5ac70f0Sopenharmony_ci data->count = count; 1615d5ac70f0Sopenharmony_ci data->choices = choices; 1616d5ac70f0Sopenharmony_ci s += var; 1617d5ac70f0Sopenharmony_ci s->valid = 1; 1618d5ac70f0Sopenharmony_ci s->order = order; 1619d5ac70f0Sopenharmony_ci s->next_value = snd_pcm_hw_strategy_simple_choices_next_value; 1620d5ac70f0Sopenharmony_ci s->min_badness = snd_pcm_hw_strategy_simple_choices_min_badness; 1621d5ac70f0Sopenharmony_ci s->private_data = data; 1622d5ac70f0Sopenharmony_ci s->free = snd_pcm_hw_strategy_simple_choices_free; 1623d5ac70f0Sopenharmony_ci return 0; 1624d5ac70f0Sopenharmony_ci} 1625d5ac70f0Sopenharmony_ci 1626d5ac70f0Sopenharmony_ciint snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm, 1627d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *fail, 1628d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *success, 1629d5ac70f0Sopenharmony_ci unsigned int depth, 1630d5ac70f0Sopenharmony_ci snd_output_t *out) 1631d5ac70f0Sopenharmony_ci{ 1632d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var; 1633d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t i; 1634d5ac70f0Sopenharmony_ci if (depth < 1) 1635d5ac70f0Sopenharmony_ci return -ENOENT; 1636d5ac70f0Sopenharmony_ci for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) { 1637d5ac70f0Sopenharmony_ci int err; 1638d5ac70f0Sopenharmony_ci i = *success; 1639d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_copy(&i, var, fail); 1640d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, &i); 1641d5ac70f0Sopenharmony_ci if (err == 0 && 1642d5ac70f0Sopenharmony_ci snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0) 1643d5ac70f0Sopenharmony_ci continue; 1644d5ac70f0Sopenharmony_ci snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(var)); 1645d5ac70f0Sopenharmony_ci snd_pcm_hw_param_dump(fail, var, out); 1646d5ac70f0Sopenharmony_ci snd_output_putc(out, '\n'); 1647d5ac70f0Sopenharmony_ci return 0; 1648d5ac70f0Sopenharmony_ci } 1649d5ac70f0Sopenharmony_ci return -ENOENT; 1650d5ac70f0Sopenharmony_ci} 1651d5ac70f0Sopenharmony_ci 1652d5ac70f0Sopenharmony_ciint snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm, 1653d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *fail, 1654d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *success, 1655d5ac70f0Sopenharmony_ci unsigned int depth, 1656d5ac70f0Sopenharmony_ci snd_output_t *out) 1657d5ac70f0Sopenharmony_ci{ 1658d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t i, any; 1659d5ac70f0Sopenharmony_ci int err; 1660d5ac70f0Sopenharmony_ci snd_pcm_hw_param_t var; 1661d5ac70f0Sopenharmony_ci int done = 0; 1662d5ac70f0Sopenharmony_ci assert(pcm && fail); 1663d5ac70f0Sopenharmony_ci for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) { 1664d5ac70f0Sopenharmony_ci if (!snd_pcm_hw_param_empty(fail, var)) 1665d5ac70f0Sopenharmony_ci continue; 1666d5ac70f0Sopenharmony_ci snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var)); 1667d5ac70f0Sopenharmony_ci done = 1; 1668d5ac70f0Sopenharmony_ci } 1669d5ac70f0Sopenharmony_ci if (done) 1670d5ac70f0Sopenharmony_ci return 0; 1671d5ac70f0Sopenharmony_ci i = *fail; 1672d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, &i); 1673d5ac70f0Sopenharmony_ci if (err == 0) { 1674d5ac70f0Sopenharmony_ci snd_output_printf(out, "Configuration is virtually correct\n"); 1675d5ac70f0Sopenharmony_ci return 0; 1676d5ac70f0Sopenharmony_ci } 1677d5ac70f0Sopenharmony_ci if (!success) { 1678d5ac70f0Sopenharmony_ci snd_pcm_hw_params_any(pcm, &any); 1679d5ac70f0Sopenharmony_ci success = &any; 1680d5ac70f0Sopenharmony_ci } 1681d5ac70f0Sopenharmony_ci return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out); 1682d5ac70f0Sopenharmony_ci} 1683d5ac70f0Sopenharmony_ci 1684d5ac70f0Sopenharmony_ci#endif 1685d5ac70f0Sopenharmony_ci 1686d5ac70f0Sopenharmony_citypedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t; 1687d5ac70f0Sopenharmony_ci 1688d5ac70f0Sopenharmony_citypedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params, 1689d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule); 1690d5ac70f0Sopenharmony_ci 1691d5ac70f0Sopenharmony_cistruct _snd_pcm_hw_rule { 1692d5ac70f0Sopenharmony_ci int var; 1693d5ac70f0Sopenharmony_ci snd_pcm_hw_rule_func_t func; 1694d5ac70f0Sopenharmony_ci int deps[4]; 1695d5ac70f0Sopenharmony_ci void *private_data; 1696d5ac70f0Sopenharmony_ci}; 1697d5ac70f0Sopenharmony_ci 1698d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params, 1699d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule) 1700d5ac70f0Sopenharmony_ci{ 1701d5ac70f0Sopenharmony_ci snd_interval_t t; 1702d5ac70f0Sopenharmony_ci snd_interval_mul(hw_param_interval_c(params, rule->deps[0]), 1703d5ac70f0Sopenharmony_ci hw_param_interval_c(params, rule->deps[1]), &t); 1704d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), &t); 1705d5ac70f0Sopenharmony_ci} 1706d5ac70f0Sopenharmony_ci 1707d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params, 1708d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule) 1709d5ac70f0Sopenharmony_ci{ 1710d5ac70f0Sopenharmony_ci snd_interval_t t; 1711d5ac70f0Sopenharmony_ci snd_interval_div(hw_param_interval_c(params, rule->deps[0]), 1712d5ac70f0Sopenharmony_ci hw_param_interval_c(params, rule->deps[1]), &t); 1713d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), &t); 1714d5ac70f0Sopenharmony_ci} 1715d5ac70f0Sopenharmony_ci 1716d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params, 1717d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule) 1718d5ac70f0Sopenharmony_ci{ 1719d5ac70f0Sopenharmony_ci snd_interval_t t; 1720d5ac70f0Sopenharmony_ci snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]), 1721d5ac70f0Sopenharmony_ci hw_param_interval_c(params, rule->deps[1]), 1722d5ac70f0Sopenharmony_ci (unsigned long) rule->private_data, &t); 1723d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), &t); 1724d5ac70f0Sopenharmony_ci} 1725d5ac70f0Sopenharmony_ci 1726d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params, 1727d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule) 1728d5ac70f0Sopenharmony_ci{ 1729d5ac70f0Sopenharmony_ci snd_interval_t t; 1730d5ac70f0Sopenharmony_ci snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]), 1731d5ac70f0Sopenharmony_ci (unsigned long) rule->private_data, 1732d5ac70f0Sopenharmony_ci hw_param_interval_c(params, rule->deps[1]), &t); 1733d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), &t); 1734d5ac70f0Sopenharmony_ci} 1735d5ac70f0Sopenharmony_ci 1736d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params, 1737d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule) 1738d5ac70f0Sopenharmony_ci{ 1739d5ac70f0Sopenharmony_ci int changed = 0; 1740d5ac70f0Sopenharmony_ci snd_pcm_format_t k; 1741d5ac70f0Sopenharmony_ci snd_mask_t *mask = hw_param_mask(params, rule->var); 1742d5ac70f0Sopenharmony_ci snd_interval_t *i = hw_param_interval(params, rule->deps[0]); 1743d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) { 1744d5ac70f0Sopenharmony_ci int bits; 1745d5ac70f0Sopenharmony_ci if (!snd_pcm_format_mask_test(mask, k)) 1746d5ac70f0Sopenharmony_ci continue; 1747d5ac70f0Sopenharmony_ci bits = snd_pcm_format_physical_width(k); 1748d5ac70f0Sopenharmony_ci if (bits < 0) 1749d5ac70f0Sopenharmony_ci continue; 1750d5ac70f0Sopenharmony_ci if (!snd_interval_test(i, (unsigned int) bits)) { 1751d5ac70f0Sopenharmony_ci snd_pcm_format_mask_reset(mask, k); 1752d5ac70f0Sopenharmony_ci if (snd_mask_empty(mask)) 1753d5ac70f0Sopenharmony_ci return -EINVAL; 1754d5ac70f0Sopenharmony_ci changed = 1; 1755d5ac70f0Sopenharmony_ci } 1756d5ac70f0Sopenharmony_ci } 1757d5ac70f0Sopenharmony_ci return changed; 1758d5ac70f0Sopenharmony_ci} 1759d5ac70f0Sopenharmony_ci 1760d5ac70f0Sopenharmony_ci 1761d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params, 1762d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *rule) 1763d5ac70f0Sopenharmony_ci{ 1764d5ac70f0Sopenharmony_ci unsigned int min, max; 1765d5ac70f0Sopenharmony_ci snd_pcm_format_t k; 1766d5ac70f0Sopenharmony_ci snd_interval_t *i = hw_param_interval(params, rule->var); 1767d5ac70f0Sopenharmony_ci snd_mask_t *mask = hw_param_mask(params, rule->deps[0]); 1768d5ac70f0Sopenharmony_ci int c, changed = 0; 1769d5ac70f0Sopenharmony_ci min = UINT_MAX; 1770d5ac70f0Sopenharmony_ci max = 0; 1771d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) { 1772d5ac70f0Sopenharmony_ci int bits; 1773d5ac70f0Sopenharmony_ci if (!snd_pcm_format_mask_test(mask, k)) 1774d5ac70f0Sopenharmony_ci continue; 1775d5ac70f0Sopenharmony_ci bits = snd_pcm_format_physical_width(k); 1776d5ac70f0Sopenharmony_ci if (bits < 0) 1777d5ac70f0Sopenharmony_ci continue; 1778d5ac70f0Sopenharmony_ci if (min > (unsigned)bits) 1779d5ac70f0Sopenharmony_ci min = bits; 1780d5ac70f0Sopenharmony_ci if (max < (unsigned)bits) 1781d5ac70f0Sopenharmony_ci max = bits; 1782d5ac70f0Sopenharmony_ci } 1783d5ac70f0Sopenharmony_ci c = snd_interval_refine_min(i, min, 0); 1784d5ac70f0Sopenharmony_ci if (c < 0) 1785d5ac70f0Sopenharmony_ci return c; 1786d5ac70f0Sopenharmony_ci if (c) 1787d5ac70f0Sopenharmony_ci changed = 1; 1788d5ac70f0Sopenharmony_ci c = snd_interval_refine_max(i, max, 0); 1789d5ac70f0Sopenharmony_ci if (c < 0) 1790d5ac70f0Sopenharmony_ci return c; 1791d5ac70f0Sopenharmony_ci if (c) 1792d5ac70f0Sopenharmony_ci changed = 1; 1793d5ac70f0Sopenharmony_ci return changed; 1794d5ac70f0Sopenharmony_ci} 1795d5ac70f0Sopenharmony_ci 1796d5ac70f0Sopenharmony_cistatic const snd_pcm_hw_rule_t refine_rules[] = { 1797d5ac70f0Sopenharmony_ci { 1798d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_FORMAT, 1799d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_format, 1800d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 }, 1801d5ac70f0Sopenharmony_ci .private_data = 0, 1802d5ac70f0Sopenharmony_ci }, 1803d5ac70f0Sopenharmony_ci { 1804d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_SAMPLE_BITS, 1805d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_sample_bits, 1806d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_FORMAT, 1807d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_SAMPLE_BITS, -1 }, 1808d5ac70f0Sopenharmony_ci .private_data = 0, 1809d5ac70f0Sopenharmony_ci }, 1810d5ac70f0Sopenharmony_ci { 1811d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_SAMPLE_BITS, 1812d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_div, 1813d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_FRAME_BITS, 1814d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, -1 }, 1815d5ac70f0Sopenharmony_ci .private_data = 0, 1816d5ac70f0Sopenharmony_ci }, 1817d5ac70f0Sopenharmony_ci { 1818d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_FRAME_BITS, 1819d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mul, 1820d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, 1821d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, -1 }, 1822d5ac70f0Sopenharmony_ci .private_data = 0, 1823d5ac70f0Sopenharmony_ci }, 1824d5ac70f0Sopenharmony_ci { 1825d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_FRAME_BITS, 1826d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1827d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_BYTES, 1828d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, -1 }, 1829d5ac70f0Sopenharmony_ci .private_data = (void*) 8, 1830d5ac70f0Sopenharmony_ci }, 1831d5ac70f0Sopenharmony_ci { 1832d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_FRAME_BITS, 1833d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1834d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_BYTES, 1835d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_SIZE, -1 }, 1836d5ac70f0Sopenharmony_ci .private_data = (void*) 8, 1837d5ac70f0Sopenharmony_ci }, 1838d5ac70f0Sopenharmony_ci { 1839d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_CHANNELS, 1840d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_div, 1841d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_FRAME_BITS, 1842d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_SAMPLE_BITS, -1 }, 1843d5ac70f0Sopenharmony_ci .private_data = 0, 1844d5ac70f0Sopenharmony_ci }, 1845d5ac70f0Sopenharmony_ci { 1846d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_RATE, 1847d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1848d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, 1849d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_TIME, -1 }, 1850d5ac70f0Sopenharmony_ci .private_data = (void*) 1000000, 1851d5ac70f0Sopenharmony_ci }, 1852d5ac70f0Sopenharmony_ci { 1853d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_RATE, 1854d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1855d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, 1856d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_TIME, -1 }, 1857d5ac70f0Sopenharmony_ci .private_data = (void*) 1000000, 1858d5ac70f0Sopenharmony_ci }, 1859d5ac70f0Sopenharmony_ci { 1860d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_PERIODS, 1861d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_div, 1862d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, 1863d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, -1 }, 1864d5ac70f0Sopenharmony_ci .private_data = 0, 1865d5ac70f0Sopenharmony_ci }, 1866d5ac70f0Sopenharmony_ci { 1867d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_PERIOD_SIZE, 1868d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_div, 1869d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, 1870d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS, -1 }, 1871d5ac70f0Sopenharmony_ci .private_data = 0, 1872d5ac70f0Sopenharmony_ci }, 1873d5ac70f0Sopenharmony_ci { 1874d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_PERIOD_SIZE, 1875d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1876d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_BYTES, 1877d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FRAME_BITS, -1 }, 1878d5ac70f0Sopenharmony_ci .private_data = (void*) 8, 1879d5ac70f0Sopenharmony_ci }, 1880d5ac70f0Sopenharmony_ci { 1881d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_PERIOD_SIZE, 1882d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_muldivk, 1883d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_TIME, 1884d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, -1 }, 1885d5ac70f0Sopenharmony_ci .private_data = (void*) 1000000, 1886d5ac70f0Sopenharmony_ci }, 1887d5ac70f0Sopenharmony_ci { 1888d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_BUFFER_SIZE, 1889d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mul, 1890d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, 1891d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS, -1 }, 1892d5ac70f0Sopenharmony_ci .private_data = 0, 1893d5ac70f0Sopenharmony_ci }, 1894d5ac70f0Sopenharmony_ci { 1895d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_BUFFER_SIZE, 1896d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1897d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_BYTES, 1898d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FRAME_BITS, -1 }, 1899d5ac70f0Sopenharmony_ci .private_data = (void*) 8, 1900d5ac70f0Sopenharmony_ci }, 1901d5ac70f0Sopenharmony_ci { 1902d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_BUFFER_SIZE, 1903d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_muldivk, 1904d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_TIME, 1905d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, -1 }, 1906d5ac70f0Sopenharmony_ci .private_data = (void*) 1000000, 1907d5ac70f0Sopenharmony_ci }, 1908d5ac70f0Sopenharmony_ci { 1909d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_PERIOD_BYTES, 1910d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_muldivk, 1911d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, 1912d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FRAME_BITS, -1 }, 1913d5ac70f0Sopenharmony_ci .private_data = (void*) 8, 1914d5ac70f0Sopenharmony_ci }, 1915d5ac70f0Sopenharmony_ci { 1916d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_BUFFER_BYTES, 1917d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_muldivk, 1918d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, 1919d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FRAME_BITS, -1 }, 1920d5ac70f0Sopenharmony_ci .private_data = (void*) 8, 1921d5ac70f0Sopenharmony_ci }, 1922d5ac70f0Sopenharmony_ci { 1923d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_PERIOD_TIME, 1924d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1925d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, 1926d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, -1 }, 1927d5ac70f0Sopenharmony_ci .private_data = (void*) 1000000, 1928d5ac70f0Sopenharmony_ci }, 1929d5ac70f0Sopenharmony_ci { 1930d5ac70f0Sopenharmony_ci .var = SND_PCM_HW_PARAM_BUFFER_TIME, 1931d5ac70f0Sopenharmony_ci .func = snd_pcm_hw_rule_mulkdiv, 1932d5ac70f0Sopenharmony_ci .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, 1933d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, -1 }, 1934d5ac70f0Sopenharmony_ci .private_data = (void*) 1000000, 1935d5ac70f0Sopenharmony_ci }, 1936d5ac70f0Sopenharmony_ci}; 1937d5ac70f0Sopenharmony_ci 1938d5ac70f0Sopenharmony_ci#define RULES (sizeof(refine_rules) / sizeof(refine_rules[0])) 1939d5ac70f0Sopenharmony_ci#define PCM_BIT(x) \ 1940d5ac70f0Sopenharmony_ci (1U << ((x) < 32 ? (x) : ((x) - 32))) 1941d5ac70f0Sopenharmony_ci 1942d5ac70f0Sopenharmony_cistatic const snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = { 1943d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = { 1944d5ac70f0Sopenharmony_ci .bits = { 1945d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | 1946d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) | 1947d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_ACCESS_MMAP_COMPLEX) | 1948d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED) | 1949d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) 1950d5ac70f0Sopenharmony_ci }, 1951d5ac70f0Sopenharmony_ci }, 1952d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = { 1953d5ac70f0Sopenharmony_ci .bits = { 1954d5ac70f0Sopenharmony_ci /* first 32bits */ 1955d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S8) | 1956d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U8) | 1957d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S16_LE) | 1958d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S16_BE) | 1959d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U16_LE) | 1960d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U16_BE) | 1961d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S24_LE) | 1962d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S24_BE) | 1963d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U24_LE) | 1964d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U24_BE) | 1965d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S32_LE) | 1966d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S32_BE) | 1967d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U32_LE) | 1968d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U32_BE) | 1969d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_LE) | 1970d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_BE) | 1971d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_LE) | 1972d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_BE) | 1973d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) | 1974d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) | 1975d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_MU_LAW) | 1976d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_A_LAW) | 1977d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_IMA_ADPCM) | 1978d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_MPEG) | 1979d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_GSM) | 1980d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S20_LE) | 1981d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S20_BE) | 1982d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U20_LE) | 1983d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U20_BE) | 1984d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_SPECIAL), 1985d5ac70f0Sopenharmony_ci /* second 32bits */ 1986d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S24_3LE) | 1987d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S24_3BE) | 1988d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U24_3LE) | 1989d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U24_3BE) | 1990d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S20_3LE) | 1991d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S20_3BE) | 1992d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U20_3LE) | 1993d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U20_3BE) | 1994d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S18_3LE) | 1995d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_S18_3BE) | 1996d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U18_3LE) | 1997d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_U18_3BE) | 1998d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_G723_24) | 1999d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_G723_24) | 2000d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_G723_40) | 2001d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_G723_40) | 2002d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_DSD_U8) | 2003d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_LE) | 2004d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_LE) | 2005d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_BE) | 2006d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_BE) 2007d5ac70f0Sopenharmony_ci }, 2008d5ac70f0Sopenharmony_ci }, 2009d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = { 2010d5ac70f0Sopenharmony_ci .bits = { 2011d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_SUBFORMAT_STD) | 2012d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_SUBFORMAT_MSBITS_MAX) | 2013d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_SUBFORMAT_MSBITS_20) | 2014d5ac70f0Sopenharmony_ci PCM_BIT(SNDRV_PCM_SUBFORMAT_MSBITS_24), 2015d5ac70f0Sopenharmony_ci }, 2016d5ac70f0Sopenharmony_ci }, 2017d5ac70f0Sopenharmony_ci}; 2018d5ac70f0Sopenharmony_ci 2019d5ac70f0Sopenharmony_cistatic const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = { 2020d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2021d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2022d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, 2023d5ac70f0Sopenharmony_ci }, 2024d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2025d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2026d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, 2027d5ac70f0Sopenharmony_ci }, 2028d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2029d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2030d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, 2031d5ac70f0Sopenharmony_ci }, 2032d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2033d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2034d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2035d5ac70f0Sopenharmony_ci }, 2036d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2037d5ac70f0Sopenharmony_ci .min = 0, .max = UINT_MAX, 2038d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2039d5ac70f0Sopenharmony_ci }, 2040d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2041d5ac70f0Sopenharmony_ci .min = 0, .max = UINT_MAX, 2042d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2043d5ac70f0Sopenharmony_ci }, 2044d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2045d5ac70f0Sopenharmony_ci .min = 0, .max = UINT_MAX, 2046d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2047d5ac70f0Sopenharmony_ci }, 2048d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2049d5ac70f0Sopenharmony_ci .min = 0, .max = UINT_MAX, 2050d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2051d5ac70f0Sopenharmony_ci }, 2052d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2053d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2054d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2055d5ac70f0Sopenharmony_ci }, 2056d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2057d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2058d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, 2059d5ac70f0Sopenharmony_ci }, 2060d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2061d5ac70f0Sopenharmony_ci .min = 1, .max = UINT_MAX, 2062d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, 2063d5ac70f0Sopenharmony_ci }, 2064d5ac70f0Sopenharmony_ci [SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { 2065d5ac70f0Sopenharmony_ci .min = 0, .max = UINT_MAX, 2066d5ac70f0Sopenharmony_ci .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, 2067d5ac70f0Sopenharmony_ci }, 2068d5ac70f0Sopenharmony_ci}; 2069d5ac70f0Sopenharmony_ci 2070d5ac70f0Sopenharmony_ci#if 0 2071d5ac70f0Sopenharmony_ci#define RULES_DEBUG 2072d5ac70f0Sopenharmony_ci#endif 2073d5ac70f0Sopenharmony_ci 2074d5ac70f0Sopenharmony_ciint snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) 2075d5ac70f0Sopenharmony_ci{ 2076d5ac70f0Sopenharmony_ci unsigned int k; 2077d5ac70f0Sopenharmony_ci snd_interval_t *i; 2078d5ac70f0Sopenharmony_ci snd_mask_t *m; 2079d5ac70f0Sopenharmony_ci unsigned int rstamps[RULES]; 2080d5ac70f0Sopenharmony_ci unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1]; 2081d5ac70f0Sopenharmony_ci unsigned int stamp = 2; 2082d5ac70f0Sopenharmony_ci int changed, again; 2083d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2084d5ac70f0Sopenharmony_ci snd_output_t *log; 2085d5ac70f0Sopenharmony_ci snd_output_stdio_attach(&log, stderr, 0); 2086d5ac70f0Sopenharmony_ci snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name); 2087d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2088d5ac70f0Sopenharmony_ci#endif 2089d5ac70f0Sopenharmony_ci 2090d5ac70f0Sopenharmony_ci for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) { 2091d5ac70f0Sopenharmony_ci if (!(params->rmask & (1 << k))) 2092d5ac70f0Sopenharmony_ci continue; 2093d5ac70f0Sopenharmony_ci changed = snd_mask_refine(hw_param_mask(params, k), 2094d5ac70f0Sopenharmony_ci &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]); 2095d5ac70f0Sopenharmony_ci if (changed) 2096d5ac70f0Sopenharmony_ci params->cmask |= 1 << k; 2097d5ac70f0Sopenharmony_ci if (changed < 0) 2098d5ac70f0Sopenharmony_ci goto _err; 2099d5ac70f0Sopenharmony_ci } 2100d5ac70f0Sopenharmony_ci 2101d5ac70f0Sopenharmony_ci for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) { 2102d5ac70f0Sopenharmony_ci if (!(params->rmask & (1 << k))) 2103d5ac70f0Sopenharmony_ci continue; 2104d5ac70f0Sopenharmony_ci changed = snd_interval_refine(hw_param_interval(params, k), 2105d5ac70f0Sopenharmony_ci &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]); 2106d5ac70f0Sopenharmony_ci if (changed) 2107d5ac70f0Sopenharmony_ci params->cmask |= 1 << k; 2108d5ac70f0Sopenharmony_ci if (changed < 0) 2109d5ac70f0Sopenharmony_ci goto _err; 2110d5ac70f0Sopenharmony_ci } 2111d5ac70f0Sopenharmony_ci 2112d5ac70f0Sopenharmony_ci for (k = 0; k < RULES; k++) 2113d5ac70f0Sopenharmony_ci rstamps[k] = 0; 2114d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) 2115d5ac70f0Sopenharmony_ci vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; 2116d5ac70f0Sopenharmony_ci do { 2117d5ac70f0Sopenharmony_ci again = 0; 2118d5ac70f0Sopenharmony_ci for (k = 0; k < RULES; k++) { 2119d5ac70f0Sopenharmony_ci const snd_pcm_hw_rule_t *r = &refine_rules[k]; 2120d5ac70f0Sopenharmony_ci unsigned int d; 2121d5ac70f0Sopenharmony_ci int doit = 0; 2122d5ac70f0Sopenharmony_ci for (d = 0; r->deps[d] >= 0; d++) { 2123d5ac70f0Sopenharmony_ci if (vstamps[r->deps[d]] > rstamps[k]) { 2124d5ac70f0Sopenharmony_ci doit = 1; 2125d5ac70f0Sopenharmony_ci break; 2126d5ac70f0Sopenharmony_ci } 2127d5ac70f0Sopenharmony_ci } 2128d5ac70f0Sopenharmony_ci if (!doit) 2129d5ac70f0Sopenharmony_ci continue; 2130d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2131d5ac70f0Sopenharmony_ci snd_output_printf(log, "Rule %d (%p): ", k, r->func); 2132d5ac70f0Sopenharmony_ci if (r->var >= 0) { 2133d5ac70f0Sopenharmony_ci snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var)); 2134d5ac70f0Sopenharmony_ci snd_pcm_hw_param_dump(params, r->var, log); 2135d5ac70f0Sopenharmony_ci snd_output_puts(log, " -> "); 2136d5ac70f0Sopenharmony_ci } 2137d5ac70f0Sopenharmony_ci#endif 2138d5ac70f0Sopenharmony_ci changed = r->func(params, r); 2139d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2140d5ac70f0Sopenharmony_ci if (r->var >= 0) 2141d5ac70f0Sopenharmony_ci snd_pcm_hw_param_dump(params, r->var, log); 2142d5ac70f0Sopenharmony_ci for (d = 0; r->deps[d] >= 0; d++) { 2143d5ac70f0Sopenharmony_ci snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d])); 2144d5ac70f0Sopenharmony_ci snd_pcm_hw_param_dump(params, r->deps[d], log); 2145d5ac70f0Sopenharmony_ci } 2146d5ac70f0Sopenharmony_ci snd_output_putc(log, '\n'); 2147d5ac70f0Sopenharmony_ci#endif 2148d5ac70f0Sopenharmony_ci rstamps[k] = stamp; 2149d5ac70f0Sopenharmony_ci if (changed && r->var >= 0) { 2150d5ac70f0Sopenharmony_ci params->cmask |= 1 << r->var; 2151d5ac70f0Sopenharmony_ci vstamps[r->var] = stamp; 2152d5ac70f0Sopenharmony_ci again = 1; 2153d5ac70f0Sopenharmony_ci } 2154d5ac70f0Sopenharmony_ci if (changed < 0) 2155d5ac70f0Sopenharmony_ci goto _err; 2156d5ac70f0Sopenharmony_ci stamp++; 2157d5ac70f0Sopenharmony_ci } 2158d5ac70f0Sopenharmony_ci } while (again); 2159d5ac70f0Sopenharmony_ci if (!params->msbits) { 2160d5ac70f0Sopenharmony_ci i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS); 2161d5ac70f0Sopenharmony_ci if (snd_interval_single(i)) 2162d5ac70f0Sopenharmony_ci params->msbits = snd_interval_value(i); 2163d5ac70f0Sopenharmony_ci m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); 2164d5ac70f0Sopenharmony_ci if (snd_mask_single(m)) { 2165d5ac70f0Sopenharmony_ci snd_pcm_format_t format = snd_mask_min(m); 2166d5ac70f0Sopenharmony_ci params->msbits = snd_pcm_format_width(format); 2167d5ac70f0Sopenharmony_ci } 2168d5ac70f0Sopenharmony_ci } 2169d5ac70f0Sopenharmony_ci 2170d5ac70f0Sopenharmony_ci if (!params->rate_den) { 2171d5ac70f0Sopenharmony_ci i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE); 2172d5ac70f0Sopenharmony_ci if (snd_interval_single(i)) { 2173d5ac70f0Sopenharmony_ci params->rate_num = snd_interval_value(i); 2174d5ac70f0Sopenharmony_ci params->rate_den = 1; 2175d5ac70f0Sopenharmony_ci } 2176d5ac70f0Sopenharmony_ci } 2177d5ac70f0Sopenharmony_ci params->rmask = 0; 2178d5ac70f0Sopenharmony_ci return 0; 2179d5ac70f0Sopenharmony_ci _err: 2180d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2181d5ac70f0Sopenharmony_ci snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed); 2182d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2183d5ac70f0Sopenharmony_ci snd_output_close(log); 2184d5ac70f0Sopenharmony_ci#endif 2185d5ac70f0Sopenharmony_ci return changed; 2186d5ac70f0Sopenharmony_ci} 2187d5ac70f0Sopenharmony_ci 2188d5ac70f0Sopenharmony_ciint _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, 2189d5ac70f0Sopenharmony_ci unsigned int vars, 2190d5ac70f0Sopenharmony_ci const snd_pcm_hw_params_t *src) 2191d5ac70f0Sopenharmony_ci{ 2192d5ac70f0Sopenharmony_ci int changed, err = 0; 2193d5ac70f0Sopenharmony_ci unsigned int k; 2194d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) { 2195d5ac70f0Sopenharmony_ci if (!(vars & (1 << k))) 2196d5ac70f0Sopenharmony_ci continue; 2197d5ac70f0Sopenharmony_ci changed = _snd_pcm_hw_param_refine(params, k, src); 2198d5ac70f0Sopenharmony_ci if (changed < 0) 2199d5ac70f0Sopenharmony_ci err = changed; 2200d5ac70f0Sopenharmony_ci } 2201d5ac70f0Sopenharmony_ci params->info &= src->info; 2202d5ac70f0Sopenharmony_ci params->flags = src->flags; /* propagate all flags to slave */ 2203d5ac70f0Sopenharmony_ci return err; 2204d5ac70f0Sopenharmony_ci} 2205d5ac70f0Sopenharmony_ci 2206d5ac70f0Sopenharmony_ciint snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 2207d5ac70f0Sopenharmony_ci int (*cprepare)(snd_pcm_t *pcm, 2208d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params), 2209d5ac70f0Sopenharmony_ci int (*cchange)(snd_pcm_t *pcm, 2210d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 2211d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams), 2212d5ac70f0Sopenharmony_ci int (*sprepare)(snd_pcm_t *pcm, 2213d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params), 2214d5ac70f0Sopenharmony_ci int (*schange)(snd_pcm_t *pcm, 2215d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 2216d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams), 2217d5ac70f0Sopenharmony_ci int (*srefine)(snd_pcm_t *pcm, 2218d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams)) 2219d5ac70f0Sopenharmony_ci 2220d5ac70f0Sopenharmony_ci{ 2221d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2222d5ac70f0Sopenharmony_ci snd_output_t *log; 2223d5ac70f0Sopenharmony_ci#endif 2224d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t sparams; 2225d5ac70f0Sopenharmony_ci int err; 2226d5ac70f0Sopenharmony_ci unsigned int cmask, changed; 2227d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2228d5ac70f0Sopenharmony_ci snd_output_stdio_attach(&log, stderr, 0); 2229d5ac70f0Sopenharmony_ci#endif 2230d5ac70f0Sopenharmony_ci err = cprepare(pcm, params); 2231d5ac70f0Sopenharmony_ci if (err < 0) 2232d5ac70f0Sopenharmony_ci return err; 2233d5ac70f0Sopenharmony_ci err = sprepare(pcm, &sparams); 2234d5ac70f0Sopenharmony_ci if (err < 0) { 2235d5ac70f0Sopenharmony_ci SNDERR("Slave PCM not usable"); 2236d5ac70f0Sopenharmony_ci return err; 2237d5ac70f0Sopenharmony_ci } 2238d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2239d5ac70f0Sopenharmony_ci snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name); 2240d5ac70f0Sopenharmony_ci#endif 2241d5ac70f0Sopenharmony_ci do { 2242d5ac70f0Sopenharmony_ci cmask = params->cmask; 2243d5ac70f0Sopenharmony_ci params->cmask = 0; 2244d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2245d5ac70f0Sopenharmony_ci snd_output_printf(log, "schange '%s' (client)\n", pcm->name); 2246d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2247d5ac70f0Sopenharmony_ci snd_output_printf(log, "schange '%s' (slave)\n", pcm->name); 2248d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(&sparams, log); 2249d5ac70f0Sopenharmony_ci#endif 2250d5ac70f0Sopenharmony_ci err = schange(pcm, params, &sparams); 2251d5ac70f0Sopenharmony_ci if (err >= 0) { 2252d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2253d5ac70f0Sopenharmony_ci snd_output_printf(log, "srefine '%s' (client)\n", pcm->name); 2254d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2255d5ac70f0Sopenharmony_ci snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name); 2256d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(&sparams, log); 2257d5ac70f0Sopenharmony_ci#endif 2258d5ac70f0Sopenharmony_ci err = srefine(pcm, &sparams); 2259d5ac70f0Sopenharmony_ci if (err < 0) { 2260d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2261d5ac70f0Sopenharmony_ci snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err); 2262d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2263d5ac70f0Sopenharmony_ci snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err); 2264d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(&sparams, log); 2265d5ac70f0Sopenharmony_ci#endif 2266d5ac70f0Sopenharmony_ci cchange(pcm, params, &sparams); 2267d5ac70f0Sopenharmony_ci return err; 2268d5ac70f0Sopenharmony_ci } 2269d5ac70f0Sopenharmony_ci } else { 2270d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2271d5ac70f0Sopenharmony_ci snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err); 2272d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2273d5ac70f0Sopenharmony_ci snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err); 2274d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(&sparams, log); 2275d5ac70f0Sopenharmony_ci#endif 2276d5ac70f0Sopenharmony_ci cchange(pcm, params, &sparams); 2277d5ac70f0Sopenharmony_ci return err; 2278d5ac70f0Sopenharmony_ci } 2279d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2280d5ac70f0Sopenharmony_ci snd_output_printf(log, "cchange '%s'\n", pcm->name); 2281d5ac70f0Sopenharmony_ci#endif 2282d5ac70f0Sopenharmony_ci err = cchange(pcm, params, &sparams); 2283d5ac70f0Sopenharmony_ci if (err < 0) 2284d5ac70f0Sopenharmony_ci return err; 2285d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2286d5ac70f0Sopenharmony_ci snd_output_printf(log, "refine_soft '%s'\n", pcm->name); 2287d5ac70f0Sopenharmony_ci#endif 2288d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine_soft(pcm, params); 2289d5ac70f0Sopenharmony_ci changed = params->cmask; 2290d5ac70f0Sopenharmony_ci params->cmask |= cmask; 2291d5ac70f0Sopenharmony_ci if (err < 0) 2292d5ac70f0Sopenharmony_ci return err; 2293d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2294d5ac70f0Sopenharmony_ci snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name); 2295d5ac70f0Sopenharmony_ci#endif 2296d5ac70f0Sopenharmony_ci } while (changed); 2297d5ac70f0Sopenharmony_ci#ifdef RULES_DEBUG 2298d5ac70f0Sopenharmony_ci snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name); 2299d5ac70f0Sopenharmony_ci snd_output_close(log); 2300d5ac70f0Sopenharmony_ci#endif 2301d5ac70f0Sopenharmony_ci return 0; 2302d5ac70f0Sopenharmony_ci} 2303d5ac70f0Sopenharmony_ci 2304d5ac70f0Sopenharmony_ciint snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 2305d5ac70f0Sopenharmony_ci int (*cchange)(snd_pcm_t *pcm, 2306d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 2307d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams), 2308d5ac70f0Sopenharmony_ci int (*sprepare)(snd_pcm_t *pcm, 2309d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params), 2310d5ac70f0Sopenharmony_ci int (*schange)(snd_pcm_t *pcm, 2311d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 2312d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams), 2313d5ac70f0Sopenharmony_ci int (*sparams)(snd_pcm_t *pcm, 2314d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams)) 2315d5ac70f0Sopenharmony_ci 2316d5ac70f0Sopenharmony_ci{ 2317d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t slave_params; 2318d5ac70f0Sopenharmony_ci int err; 2319d5ac70f0Sopenharmony_ci err = sprepare(pcm, &slave_params); 2320d5ac70f0Sopenharmony_ci if (err < 0) 2321d5ac70f0Sopenharmony_ci return err; 2322d5ac70f0Sopenharmony_ci err = schange(pcm, params, &slave_params); 2323d5ac70f0Sopenharmony_ci if (err < 0) 2324d5ac70f0Sopenharmony_ci return err; 2325d5ac70f0Sopenharmony_ci err = sparams(pcm, &slave_params); 2326d5ac70f0Sopenharmony_ci if (err < 0) 2327d5ac70f0Sopenharmony_ci cchange(pcm, params, &slave_params); 2328d5ac70f0Sopenharmony_ci return err; 2329d5ac70f0Sopenharmony_ci} 2330d5ac70f0Sopenharmony_ci 2331d5ac70f0Sopenharmony_cistatic int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) 2332d5ac70f0Sopenharmony_ci{ 2333d5ac70f0Sopenharmony_ci assert(pcm && params); 2334d5ac70f0Sopenharmony_ci assert(pcm->setup); 2335d5ac70f0Sopenharmony_ci params->proto = SNDRV_PCM_VERSION; 2336d5ac70f0Sopenharmony_ci params->tstamp_mode = SND_PCM_TSTAMP_NONE; 2337d5ac70f0Sopenharmony_ci params->tstamp_type = pcm->tstamp_type; 2338d5ac70f0Sopenharmony_ci params->period_step = 1; 2339d5ac70f0Sopenharmony_ci params->sleep_min = 0; 2340d5ac70f0Sopenharmony_ci params->avail_min = pcm->period_size; 2341d5ac70f0Sopenharmony_ci params->xfer_align = 1; 2342d5ac70f0Sopenharmony_ci params->start_threshold = 1; 2343d5ac70f0Sopenharmony_ci params->stop_threshold = pcm->buffer_size; 2344d5ac70f0Sopenharmony_ci params->silence_threshold = 0; 2345d5ac70f0Sopenharmony_ci params->silence_size = 0; 2346d5ac70f0Sopenharmony_ci params->boundary = pcm->buffer_size; 2347d5ac70f0Sopenharmony_ci /* this should not happen (bad child?) */ 2348d5ac70f0Sopenharmony_ci if (params->boundary == 0) 2349d5ac70f0Sopenharmony_ci return -EINVAL; 2350d5ac70f0Sopenharmony_ci while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size) 2351d5ac70f0Sopenharmony_ci params->boundary *= 2; 2352d5ac70f0Sopenharmony_ci return 0; 2353d5ac70f0Sopenharmony_ci} 2354d5ac70f0Sopenharmony_ci 2355d5ac70f0Sopenharmony_ci#if 0 2356d5ac70f0Sopenharmony_ci#define REFINE_DEBUG 2357d5ac70f0Sopenharmony_ci#endif 2358d5ac70f0Sopenharmony_ci 2359d5ac70f0Sopenharmony_ciint snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 2360d5ac70f0Sopenharmony_ci{ 2361d5ac70f0Sopenharmony_ci int res; 2362d5ac70f0Sopenharmony_ci#ifdef REFINE_DEBUG 2363d5ac70f0Sopenharmony_ci snd_output_t *log; 2364d5ac70f0Sopenharmony_ci snd_output_stdio_attach(&log, stderr, 0); 2365d5ac70f0Sopenharmony_ci#endif 2366d5ac70f0Sopenharmony_ci assert(pcm && params); 2367d5ac70f0Sopenharmony_ci#ifdef REFINE_DEBUG 2368d5ac70f0Sopenharmony_ci snd_output_printf(log, "REFINE called:\n"); 2369d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2370d5ac70f0Sopenharmony_ci#endif 2371d5ac70f0Sopenharmony_ci if (pcm->ops->hw_refine) 2372d5ac70f0Sopenharmony_ci res = pcm->ops->hw_refine(pcm->op_arg, params); 2373d5ac70f0Sopenharmony_ci else 2374d5ac70f0Sopenharmony_ci res = -ENOSYS; 2375d5ac70f0Sopenharmony_ci#ifdef REFINE_DEBUG 2376d5ac70f0Sopenharmony_ci snd_output_printf(log, "refine done - result = %i\n", res); 2377d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 2378d5ac70f0Sopenharmony_ci snd_output_close(log); 2379d5ac70f0Sopenharmony_ci#endif 2380d5ac70f0Sopenharmony_ci return res; 2381d5ac70f0Sopenharmony_ci} 2382d5ac70f0Sopenharmony_ci 2383d5ac70f0Sopenharmony_ci/* Install one of the configurations present in configuration 2384d5ac70f0Sopenharmony_ci space defined by PARAMS. 2385d5ac70f0Sopenharmony_ci The configuration chosen is that obtained fixing in this order: 2386d5ac70f0Sopenharmony_ci first access 2387d5ac70f0Sopenharmony_ci first format 2388d5ac70f0Sopenharmony_ci first subformat 2389d5ac70f0Sopenharmony_ci min channels 2390d5ac70f0Sopenharmony_ci min rate 2391d5ac70f0Sopenharmony_ci min period_size 2392d5ac70f0Sopenharmony_ci max periods 2393d5ac70f0Sopenharmony_ci Return 0 on success otherwise a negative error code 2394d5ac70f0Sopenharmony_ci*/ 2395d5ac70f0Sopenharmony_ciint _snd_pcm_hw_params_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 2396d5ac70f0Sopenharmony_ci{ 2397d5ac70f0Sopenharmony_ci int err; 2398d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t sw; 2399d5ac70f0Sopenharmony_ci int fb, min_align; 2400d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine(pcm, params); 2401d5ac70f0Sopenharmony_ci if (err < 0) 2402d5ac70f0Sopenharmony_ci return err; 2403d5ac70f0Sopenharmony_ci snd_pcm_hw_params_choose(pcm, params); 2404d5ac70f0Sopenharmony_ci if (pcm->setup) { 2405d5ac70f0Sopenharmony_ci err = snd_pcm_hw_free(pcm); 2406d5ac70f0Sopenharmony_ci if (err < 0) 2407d5ac70f0Sopenharmony_ci return err; 2408d5ac70f0Sopenharmony_ci } 2409d5ac70f0Sopenharmony_ci if (pcm->ops->hw_params) 2410d5ac70f0Sopenharmony_ci err = pcm->ops->hw_params(pcm->op_arg, params); 2411d5ac70f0Sopenharmony_ci else 2412d5ac70f0Sopenharmony_ci err = -ENOSYS; 2413d5ac70f0Sopenharmony_ci if (err < 0) 2414d5ac70f0Sopenharmony_ci return err; 2415d5ac70f0Sopenharmony_ci 2416d5ac70f0Sopenharmony_ci pcm->setup = 1; 2417d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access); 2418d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format); 2419d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat); 2420d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels); 2421d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0); 2422d5ac70f0Sopenharmony_ci snd_interval_copy(&pcm->periods, ¶ms->intervals[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL]); 2423d5ac70f0Sopenharmony_ci snd_interval_copy(&pcm->buffer_time, ¶ms->intervals[SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL]); 2424d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0); 2425d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0); 2426d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size); 2427d5ac70f0Sopenharmony_ci pcm->sample_bits = snd_pcm_format_physical_width(pcm->format); 2428d5ac70f0Sopenharmony_ci pcm->frame_bits = pcm->sample_bits * pcm->channels; 2429d5ac70f0Sopenharmony_ci fb = pcm->frame_bits; 2430d5ac70f0Sopenharmony_ci min_align = 1; 2431d5ac70f0Sopenharmony_ci while (fb % 8) { 2432d5ac70f0Sopenharmony_ci fb *= 2; 2433d5ac70f0Sopenharmony_ci min_align *= 2; 2434d5ac70f0Sopenharmony_ci } 2435d5ac70f0Sopenharmony_ci pcm->min_align = min_align; 2436d5ac70f0Sopenharmony_ci 2437d5ac70f0Sopenharmony_ci pcm->hw_flags = params->flags; 2438d5ac70f0Sopenharmony_ci pcm->info = params->info; 2439d5ac70f0Sopenharmony_ci pcm->msbits = params->msbits; 2440d5ac70f0Sopenharmony_ci pcm->rate_num = params->rate_num; 2441d5ac70f0Sopenharmony_ci pcm->rate_den = params->rate_den; 2442d5ac70f0Sopenharmony_ci pcm->fifo_size = params->fifo_size; 2443d5ac70f0Sopenharmony_ci 2444d5ac70f0Sopenharmony_ci /* Default sw params */ 2445d5ac70f0Sopenharmony_ci memset(&sw, 0, sizeof(sw)); 2446d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params_default(pcm, &sw); 2447d5ac70f0Sopenharmony_ci if (err < 0) 2448d5ac70f0Sopenharmony_ci return err; 2449d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params(pcm, &sw); 2450d5ac70f0Sopenharmony_ci if (err < 0) 2451d5ac70f0Sopenharmony_ci return err; 2452d5ac70f0Sopenharmony_ci 2453d5ac70f0Sopenharmony_ci if (pcm->mmap_rw || 2454d5ac70f0Sopenharmony_ci pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED || 2455d5ac70f0Sopenharmony_ci pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED || 2456d5ac70f0Sopenharmony_ci pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) { 2457d5ac70f0Sopenharmony_ci err = snd_pcm_mmap(pcm); 2458d5ac70f0Sopenharmony_ci } 2459d5ac70f0Sopenharmony_ci if (err < 0) 2460d5ac70f0Sopenharmony_ci return err; 2461d5ac70f0Sopenharmony_ci return 0; 2462d5ac70f0Sopenharmony_ci} 2463d5ac70f0Sopenharmony_ci 2464