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