1 /*- 2 * Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #ifdef HAVE_KERNEL_OPTION_HEADERS 28 #include "opt_snd.h" 29 #endif 30 31 #include <dev/sound/pcm/sound.h> 32 33 #include "feeder_if.h" 34 35 SND_DECLARE_FILE("$FreeBSD$"); 36 37 /* chain state */ 38 struct feeder_chain_state { 39 uint32_t afmt; /* audio format */ 40 uint32_t rate; /* sampling rate */ 41 struct pcmchan_matrix *matrix; /* matrix map */ 42 }; 43 44 /* 45 * chain descriptor that will be passed around from the beginning until the 46 * end of chain process. 47 */ 48 struct feeder_chain_desc { 49 struct feeder_chain_state origin; /* original state */ 50 struct feeder_chain_state current; /* current state */ 51 struct feeder_chain_state target; /* target state */ 52 struct pcm_feederdesc desc; /* feeder descriptor */ 53 uint32_t afmt_ne; /* prefered native endian */ 54 int mode; /* chain mode */ 55 int use_eq; /* need EQ? */ 56 int use_matrix; /* need channel matrixing? */ 57 int use_volume; /* need softpcmvol? */ 58 int dummy; /* dummy passthrough */ 59 int expensive; /* possibly expensive */ 60 }; 61 62 #define FEEDER_CHAIN_LEAN 0 63 #define FEEDER_CHAIN_16 1 64 #define FEEDER_CHAIN_32 2 65 #define FEEDER_CHAIN_MULTI 3 66 #define FEEDER_CHAIN_FULLMULTI 4 67 #define FEEDER_CHAIN_LAST 5 68 69 #if defined(SND_FEEDER_FULL_MULTIFORMAT) 70 #define FEEDER_CHAIN_DEFAULT FEEDER_CHAIN_FULLMULTI 71 #elif defined(SND_FEEDER_MULTIFORMAT) 72 #define FEEDER_CHAIN_DEFAULT FEEDER_CHAIN_MULTI 73 #else 74 #define FEEDER_CHAIN_DEFAULT FEEDER_CHAIN_LEAN 75 #endif 76 77 /* 78 * List of prefered formats that might be required during 79 * processing. It will be decided through snd_fmtbest(). 80 */ 81 82 /* 'Lean' mode, signed 16 or 32 bit native endian. */ 83 static uint32_t feeder_chain_formats_lean[] = { 84 AFMT_S16_NE, AFMT_S32_NE, 85 0 86 }; 87 88 /* Force everything to signed 16 bit native endian. */ 89 static uint32_t feeder_chain_formats_16[] = { 90 AFMT_S16_NE, 91 0 92 }; 93 94 /* Force everything to signed 32 bit native endian. */ 95 static uint32_t feeder_chain_formats_32[] = { 96 AFMT_S32_NE, 97 0 98 }; 99 100 /* Multiple choices, all except 8 bit. */ 101 static uint32_t feeder_chain_formats_multi[] = { 102 AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE, 103 AFMT_S24_LE, AFMT_S24_BE, AFMT_U24_LE, AFMT_U24_BE, 104 AFMT_S32_LE, AFMT_S32_BE, AFMT_U32_LE, AFMT_U32_BE, 105 0 106 }; 107 108 /* Everything that is convertible. */ 109 static uint32_t feeder_chain_formats_fullmulti[] = { 110 AFMT_S8, AFMT_U8, 111 AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE, 112 AFMT_S24_LE, AFMT_S24_BE, AFMT_U24_LE, AFMT_U24_BE, 113 AFMT_S32_LE, AFMT_S32_BE, AFMT_U32_LE, AFMT_U32_BE, 114 0 115 }; 116 117 static uint32_t *feeder_chain_formats[FEEDER_CHAIN_LAST] = { 118 [FEEDER_CHAIN_LEAN] = feeder_chain_formats_lean, 119 [FEEDER_CHAIN_16] = feeder_chain_formats_16, 120 [FEEDER_CHAIN_32] = feeder_chain_formats_32, 121 [FEEDER_CHAIN_MULTI] = feeder_chain_formats_multi, 122 [FEEDER_CHAIN_FULLMULTI] = feeder_chain_formats_fullmulti 123 }; 124 125 static int feeder_chain_mode = FEEDER_CHAIN_DEFAULT; 126 127 #if defined(_KERNEL) && defined(SND_DEBUG) && defined(SND_FEEDER_FULL_MULTIFORMAT) 128 TUNABLE_INT("hw.snd.feeder_chain_mode", &feeder_chain_mode); 129 SYSCTL_INT(_hw_snd, OID_AUTO, feeder_chain_mode, CTLFLAG_RW, 130 &feeder_chain_mode, 0, 131 "feeder chain mode " 132 "(0=lean, 1=16bit, 2=32bit, 3=multiformat, 4=fullmultiformat)"); 133 #endif 134 135 /* 136 * feeder_build_format(): Chain any format converter. 137 */ 138 static int 139 feeder_build_format(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 140 { 141 struct feeder_class *fc; 142 struct pcm_feederdesc *desc; 143 int ret; 144 145 desc = &(cdesc->desc); 146 desc->type = FEEDER_FORMAT; 147 desc->in = 0; 148 desc->out = 0; 149 desc->flags = 0; 150 151 fc = feeder_getclass(desc); 152 if (fc == NULL) { 153 device_printf(c->dev, 154 "%s(): can't find feeder_format\n", __func__); 155 return (ENOTSUP); 156 } 157 158 desc->in = cdesc->current.afmt; 159 desc->out = cdesc->target.afmt; 160 161 ret = chn_addfeeder(c, fc, desc); 162 if (ret != 0) { 163 device_printf(c->dev, 164 "%s(): can't add feeder_format\n", __func__); 165 return (ret); 166 } 167 168 c->feederflags |= 1 << FEEDER_FORMAT; 169 170 cdesc->current.afmt = cdesc->target.afmt; 171 172 return (0); 173 } 174 175 /* 176 * feeder_build_formatne(): Chain format converter that suite best for native 177 * endian format. 178 */ 179 static int 180 feeder_build_formatne(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 181 { 182 struct feeder_chain_state otarget; 183 int ret; 184 185 if (cdesc->afmt_ne == 0 || 186 AFMT_ENCODING(cdesc->current.afmt) == cdesc->afmt_ne) 187 return (0); 188 189 otarget = cdesc->target; 190 cdesc->target = cdesc->current; 191 cdesc->target.afmt = SND_FORMAT(cdesc->afmt_ne, 192 cdesc->current.matrix->channels, cdesc->current.matrix->ext); 193 194 ret = feeder_build_format(c, cdesc); 195 if (ret != 0) 196 return (ret); 197 198 cdesc->target = otarget; 199 200 return (0); 201 } 202 203 /* 204 * feeder_build_rate(): Chain sample rate converter. 205 */ 206 static int 207 feeder_build_rate(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 208 { 209 struct feeder_class *fc; 210 struct pcm_feeder *f; 211 struct pcm_feederdesc *desc; 212 int ret; 213 214 ret = feeder_build_formatne(c, cdesc); 215 if (ret != 0) 216 return (ret); 217 218 desc = &(cdesc->desc); 219 desc->type = FEEDER_RATE; 220 desc->in = 0; 221 desc->out = 0; 222 desc->flags = 0; 223 224 fc = feeder_getclass(desc); 225 if (fc == NULL) { 226 device_printf(c->dev, 227 "%s(): can't find feeder_rate\n", __func__); 228 return (ENOTSUP); 229 } 230 231 desc->in = cdesc->current.afmt; 232 desc->out = desc->in; 233 234 ret = chn_addfeeder(c, fc, desc); 235 if (ret != 0) { 236 device_printf(c->dev, 237 "%s(): can't add feeder_rate\n", __func__); 238 return (ret); 239 } 240 241 f = c->feeder; 242 243 /* 244 * If in 'dummy' mode (possibly due to passthrough mode), set the 245 * conversion quality to the lowest possible (should be fastest) since 246 * listener won't be hearing anything. Theoretically we can just 247 * disable it, but that will cause weird runtime behaviour: 248 * application appear to play something that is either too fast or too 249 * slow. 250 */ 251 if (cdesc->dummy != 0) { 252 ret = FEEDER_SET(f, FEEDRATE_QUALITY, 0); 253 if (ret != 0) { 254 device_printf(c->dev, 255 "%s(): can't set resampling quality\n", __func__); 256 return (ret); 257 } 258 } 259 260 ret = FEEDER_SET(f, FEEDRATE_SRC, cdesc->current.rate); 261 if (ret != 0) { 262 device_printf(c->dev, 263 "%s(): can't set source rate\n", __func__); 264 return (ret); 265 } 266 267 ret = FEEDER_SET(f, FEEDRATE_DST, cdesc->target.rate); 268 if (ret != 0) { 269 device_printf(c->dev, 270 "%s(): can't set destination rate\n", __func__); 271 return (ret); 272 } 273 274 c->feederflags |= 1 << FEEDER_RATE; 275 276 cdesc->current.rate = cdesc->target.rate; 277 278 return (0); 279 } 280 281 /* 282 * feeder_build_matrix(): Chain channel matrixing converter. 283 */ 284 static int 285 feeder_build_matrix(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 286 { 287 struct feeder_class *fc; 288 struct pcm_feeder *f; 289 struct pcm_feederdesc *desc; 290 int ret; 291 292 ret = feeder_build_formatne(c, cdesc); 293 if (ret != 0) 294 return (ret); 295 296 desc = &(cdesc->desc); 297 desc->type = FEEDER_MATRIX; 298 desc->in = 0; 299 desc->out = 0; 300 desc->flags = 0; 301 302 fc = feeder_getclass(desc); 303 if (fc == NULL) { 304 device_printf(c->dev, 305 "%s(): can't find feeder_matrix\n", __func__); 306 return (ENOTSUP); 307 } 308 309 desc->in = cdesc->current.afmt; 310 desc->out = SND_FORMAT(cdesc->current.afmt, 311 cdesc->target.matrix->channels, cdesc->target.matrix->ext); 312 313 ret = chn_addfeeder(c, fc, desc); 314 if (ret != 0) { 315 device_printf(c->dev, 316 "%s(): can't add feeder_matrix\n", __func__); 317 return (ret); 318 } 319 320 f = c->feeder; 321 ret = feeder_matrix_setup(f, cdesc->current.matrix, 322 cdesc->target.matrix); 323 if (ret != 0) { 324 device_printf(c->dev, 325 "%s(): feeder_matrix_setup() failed\n", __func__); 326 return (ret); 327 } 328 329 c->feederflags |= 1 << FEEDER_MATRIX; 330 331 cdesc->current.afmt = desc->out; 332 cdesc->current.matrix = cdesc->target.matrix; 333 cdesc->use_matrix = 0; 334 335 return (0); 336 } 337 338 /* 339 * feeder_build_volume(): Chain soft volume. 340 */ 341 static int 342 feeder_build_volume(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 343 { 344 struct feeder_class *fc; 345 struct pcm_feeder *f; 346 struct pcm_feederdesc *desc; 347 int ret; 348 349 ret = feeder_build_formatne(c, cdesc); 350 if (ret != 0) 351 return (ret); 352 353 desc = &(cdesc->desc); 354 desc->type = FEEDER_VOLUME; 355 desc->in = 0; 356 desc->out = 0; 357 desc->flags = 0; 358 359 fc = feeder_getclass(desc); 360 if (fc == NULL) { 361 device_printf(c->dev, 362 "%s(): can't find feeder_volume\n", __func__); 363 return (ENOTSUP); 364 } 365 366 desc->in = cdesc->current.afmt; 367 desc->out = desc->in; 368 369 ret = chn_addfeeder(c, fc, desc); 370 if (ret != 0) { 371 device_printf(c->dev, 372 "%s(): can't add feeder_volume\n", __func__); 373 return (ret); 374 } 375 376 f = c->feeder; 377 378 /* 379 * If in 'dummy' mode (possibly due to passthrough mode), set BYPASS 380 * mode since listener won't be hearing anything. Theoretically we can 381 * just disable it, but that will confuse volume per channel mixer. 382 */ 383 if (cdesc->dummy != 0) { 384 ret = FEEDER_SET(f, FEEDVOLUME_STATE, FEEDVOLUME_BYPASS); 385 if (ret != 0) { 386 device_printf(c->dev, 387 "%s(): can't set volume bypass\n", __func__); 388 return (ret); 389 } 390 } 391 392 ret = feeder_volume_apply_matrix(f, cdesc->current.matrix); 393 if (ret != 0) { 394 device_printf(c->dev, 395 "%s(): feeder_volume_apply_matrix() failed\n", __func__); 396 return (ret); 397 } 398 399 c->feederflags |= 1 << FEEDER_VOLUME; 400 401 cdesc->use_volume = 0; 402 403 return (0); 404 } 405 406 /* 407 * feeder_build_eq(): Chain parametric software equalizer. 408 */ 409 static int 410 feeder_build_eq(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 411 { 412 struct feeder_class *fc; 413 struct pcm_feeder *f; 414 struct pcm_feederdesc *desc; 415 int ret; 416 417 ret = feeder_build_formatne(c, cdesc); 418 if (ret != 0) 419 return (ret); 420 421 desc = &(cdesc->desc); 422 desc->type = FEEDER_EQ; 423 desc->in = 0; 424 desc->out = 0; 425 desc->flags = 0; 426 427 fc = feeder_getclass(desc); 428 if (fc == NULL) { 429 device_printf(c->dev, 430 "%s(): can't find feeder_eq\n", __func__); 431 return (ENOTSUP); 432 } 433 434 desc->in = cdesc->current.afmt; 435 desc->out = desc->in; 436 437 ret = chn_addfeeder(c, fc, desc); 438 if (ret != 0) { 439 device_printf(c->dev, 440 "%s(): can't add feeder_eq\n", __func__); 441 return (ret); 442 } 443 444 f = c->feeder; 445 446 ret = FEEDER_SET(f, FEEDEQ_RATE, cdesc->current.rate); 447 if (ret != 0) { 448 device_printf(c->dev, 449 "%s(): can't set rate on feeder_eq\n", __func__); 450 return (ret); 451 } 452 453 c->feederflags |= 1 << FEEDER_EQ; 454 455 cdesc->use_eq = 0; 456 457 return (0); 458 } 459 460 /* 461 * feeder_build_root(): Chain root feeder, the top, father of all. 462 */ 463 static int 464 feeder_build_root(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 465 { 466 struct feeder_class *fc; 467 int ret; 468 469 fc = feeder_getclass(NULL); 470 if (fc == NULL) { 471 device_printf(c->dev, 472 "%s(): can't find feeder_root\n", __func__); 473 return (ENOTSUP); 474 } 475 476 ret = chn_addfeeder(c, fc, NULL); 477 if (ret != 0) { 478 device_printf(c->dev, 479 "%s(): can't add feeder_root\n", __func__); 480 return (ret); 481 } 482 483 c->feederflags |= 1 << FEEDER_ROOT; 484 485 c->feeder->desc->in = cdesc->current.afmt; 486 c->feeder->desc->out = cdesc->current.afmt; 487 488 return (0); 489 } 490 491 /* 492 * feeder_build_mixer(): Chain software mixer for virtual channels. 493 */ 494 static int 495 feeder_build_mixer(struct pcm_channel *c, struct feeder_chain_desc *cdesc) 496 { 497 struct feeder_class *fc; 498 struct pcm_feederdesc *desc; 499 int ret; 500 501 desc = &(cdesc->desc); 502 desc->type = FEEDER_MIXER; 503 desc->in = 0; 504 desc->out = 0; 505 desc->flags = 0; 506 507 fc = feeder_getclass(desc); 508 if (fc == NULL) { 509 device_printf(c->dev, 510 "%s(): can't find feeder_mixer\n", __func__); 511 return (ENOTSUP); 512 } 513 514 desc->in = cdesc->current.afmt; 515 desc->out = desc->in; 516 517 ret = chn_addfeeder(c, fc, desc); 518 if (ret != 0) { 519 device_printf(c->dev, 520 "%s(): can't add feeder_mixer\n", __func__); 521 return (ret); 522 } 523 524 c->feederflags |= 1 << FEEDER_MIXER; 525 526 return (0); 527 } 528 529 /* Macrosses to ease our job doing stuffs later. */ 530 #define FEEDER_BW(c, t) ((c)->t.matrix->channels * (c)->t.rate) 531 532 #define FEEDRATE_UP(c) ((c)->target.rate > (c)->current.rate) 533 #define FEEDRATE_DOWN(c) ((c)->target.rate < (c)->current.rate) 534 #define FEEDRATE_REQUIRED(c) (FEEDRATE_UP(c) || FEEDRATE_DOWN(c)) 535 536 #define FEEDMATRIX_UP(c) ((c)->target.matrix->channels > \ 537 (c)->current.matrix->channels) 538 #define FEEDMATRIX_DOWN(c) ((c)->target.matrix->channels < \ 539 (c)->current.matrix->channels) 540 #define FEEDMATRIX_REQUIRED(c) (FEEDMATRIX_UP(c) || \ 541 FEEDMATRIX_DOWN(c) || (c)->use_matrix != 0) 542 543 #define FEEDFORMAT_REQUIRED(c) (AFMT_ENCODING((c)->current.afmt) != \ 544 AFMT_ENCODING((c)->target.afmt)) 545 546 #define FEEDVOLUME_REQUIRED(c) ((c)->use_volume != 0) 547 548 #define FEEDEQ_VALIDRATE(c, t) (feeder_eq_validrate((c)->t.rate) != 0) 549 #define FEEDEQ_ECONOMY(c) (FEEDER_BW(c, current) < FEEDER_BW(c, target)) 550 #define FEEDEQ_REQUIRED(c) ((c)->use_eq != 0 && \ 551 FEEDEQ_VALIDRATE(c, current)) 552 553 #define FEEDFORMAT_NE_REQUIRED(c) \ 554 ((c)->afmt_ne != AFMT_S32_NE && \ 555 (((c)->mode == FEEDER_CHAIN_16 && \ 556 AFMT_ENCODING((c)->current.afmt) != AFMT_S16_NE) || \ 557 ((c)->mode == FEEDER_CHAIN_32 && \ 558 AFMT_ENCODING((c)->current.afmt) != AFMT_S32_NE) || \ 559 (c)->mode == FEEDER_CHAIN_FULLMULTI || \ 560 ((c)->mode == FEEDER_CHAIN_MULTI && \ 561 ((c)->current.afmt & AFMT_8BIT)) || \ 562 ((c)->mode == FEEDER_CHAIN_LEAN && \ 563 !((c)->current.afmt & (AFMT_S16_NE | AFMT_S32_NE))))) 564 565 int 566 feeder_chain(struct pcm_channel *c) 567 { 568 struct snddev_info *d; 569 struct pcmchan_caps *caps; 570 struct feeder_chain_desc cdesc; 571 struct pcmchan_matrix *hwmatrix, *softmatrix; 572 uint32_t hwfmt, softfmt; 573 int ret; 574 575 CHN_LOCKASSERT(c); 576 577 /* Remove everything first. */ 578 while (chn_removefeeder(c) == 0) 579 ; 580 581 KASSERT(c->feeder == NULL, ("feeder chain not empty")); 582 583 /* clear and populate chain descriptor. */ 584 bzero(&cdesc, sizeof(cdesc)); 585 586 switch (feeder_chain_mode) { 587 case FEEDER_CHAIN_LEAN: 588 case FEEDER_CHAIN_16: 589 case FEEDER_CHAIN_32: 590 #if defined(SND_FEEDER_MULTIFORMAT) || defined(SND_FEEDER_FULL_MULTIFORMAT) 591 case FEEDER_CHAIN_MULTI: 592 #endif 593 #if defined(SND_FEEDER_FULL_MULTIFORMAT) 594 case FEEDER_CHAIN_FULLMULTI: 595 #endif 596 break; 597 default: 598 feeder_chain_mode = FEEDER_CHAIN_DEFAULT; 599 break; 600 } 601 602 cdesc.mode = feeder_chain_mode; 603 cdesc.expensive = 1; /* XXX faster.. */ 604 605 #define VCHAN_PASSTHROUGH(c) (((c)->flags & (CHN_F_VIRTUAL | \ 606 CHN_F_PASSTHROUGH)) == \ 607 (CHN_F_VIRTUAL | CHN_F_PASSTHROUGH)) 608 609 /* Get the best possible hardware format. */ 610 if (VCHAN_PASSTHROUGH(c)) 611 hwfmt = c->parentchannel->format; 612 else { 613 caps = chn_getcaps(c); 614 if (caps == NULL || caps->fmtlist == NULL) { 615 device_printf(c->dev, 616 "%s(): failed to get channel caps\n", __func__); 617 return (ENODEV); 618 } 619 620 if ((c->format & AFMT_PASSTHROUGH) && 621 !snd_fmtvalid(c->format, caps->fmtlist)) 622 return (ENODEV); 623 624 hwfmt = snd_fmtbest(c->format, caps->fmtlist); 625 if (hwfmt == 0 || !snd_fmtvalid(hwfmt, caps->fmtlist)) { 626 device_printf(c->dev, 627 "%s(): invalid hardware format 0x%08x\n", 628 __func__, hwfmt); 629 { 630 int i; 631 for (i = 0; caps->fmtlist[i] != 0; i++) 632 printf("0x%08x\n", caps->fmtlist[i]); 633 printf("Req: 0x%08x\n", c->format); 634 } 635 return (ENODEV); 636 } 637 } 638 639 /* 640 * The 'hardware' possibly have different intepretation of channel 641 * matrixing, so get it first ..... 642 */ 643 hwmatrix = CHANNEL_GETMATRIX(c->methods, c->devinfo, hwfmt); 644 if (hwmatrix == NULL) { 645 device_printf(c->dev, 646 "%s(): failed to acquire hw matrix [0x%08x]\n", 647 __func__, hwfmt); 648 return (ENODEV); 649 } 650 /* ..... and rebuild hwfmt. */ 651 hwfmt = SND_FORMAT(hwfmt, hwmatrix->channels, hwmatrix->ext); 652 653 /* Reset and rebuild default channel format/matrix map. */ 654 softfmt = c->format; 655 softmatrix = &c->matrix; 656 if (softmatrix->channels != AFMT_CHANNEL(softfmt) || 657 softmatrix->ext != AFMT_EXTCHANNEL(softfmt)) { 658 softmatrix = feeder_matrix_format_map(softfmt); 659 if (softmatrix == NULL) { 660 device_printf(c->dev, 661 "%s(): failed to acquire soft matrix [0x%08x]\n", 662 __func__, softfmt); 663 return (ENODEV); 664 } 665 c->matrix = *softmatrix; 666 c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL; 667 } 668 softfmt = SND_FORMAT(softfmt, softmatrix->channels, softmatrix->ext); 669 if (softfmt != c->format) 670 device_printf(c->dev, 671 "%s(): WARNING: %s Soft format 0x%08x -> 0x%08x\n", 672 __func__, CHN_DIRSTR(c), c->format, softfmt); 673 674 /* 675 * PLAY and REC are opposite. 676 */ 677 if (c->direction == PCMDIR_PLAY) { 678 cdesc.origin.afmt = softfmt; 679 cdesc.origin.matrix = softmatrix; 680 cdesc.origin.rate = c->speed; 681 cdesc.target.afmt = hwfmt; 682 cdesc.target.matrix = hwmatrix; 683 cdesc.target.rate = sndbuf_getspd(c->bufhard); 684 } else { 685 cdesc.origin.afmt = hwfmt; 686 cdesc.origin.matrix = hwmatrix; 687 cdesc.origin.rate = sndbuf_getspd(c->bufhard); 688 cdesc.target.afmt = softfmt; 689 cdesc.target.matrix = softmatrix; 690 cdesc.target.rate = c->speed; 691 } 692 693 d = c->parentsnddev; 694 695 /* 696 * If channel is in bitperfect or passthrough mode, make it appear 697 * that 'origin' and 'target' identical, skipping mostly chain 698 * procedures. 699 */ 700 if (CHN_BITPERFECT(c) || (c->format & AFMT_PASSTHROUGH)) { 701 if (c->direction == PCMDIR_PLAY) 702 cdesc.origin = cdesc.target; 703 else 704 cdesc.target = cdesc.origin; 705 c->format = cdesc.target.afmt; 706 c->speed = cdesc.target.rate; 707 } else { 708 /* hwfmt is not convertible, so 'dummy' it. */ 709 if (hwfmt & AFMT_PASSTHROUGH) 710 cdesc.dummy = 1; 711 712 if ((softfmt & AFMT_CONVERTIBLE) && 713 (((d->flags & SD_F_VPC) && !(c->flags & CHN_F_HAS_VCHAN)) || 714 (!(d->flags & SD_F_VPC) && (d->flags & SD_F_SOFTPCMVOL) && 715 !(c->flags & CHN_F_VIRTUAL)))) 716 cdesc.use_volume = 1; 717 718 if (feeder_matrix_compare(cdesc.origin.matrix, 719 cdesc.target.matrix) != 0) 720 cdesc.use_matrix = 1; 721 722 /* Soft EQ only applicable for PLAY. */ 723 if (cdesc.dummy == 0 && 724 c->direction == PCMDIR_PLAY && (d->flags & SD_F_EQ) && 725 (((d->flags & SD_F_EQ_PC) && 726 !(c->flags & CHN_F_HAS_VCHAN)) || 727 (!(d->flags & SD_F_EQ_PC) && !(c->flags & CHN_F_VIRTUAL)))) 728 cdesc.use_eq = 1; 729 730 if (FEEDFORMAT_NE_REQUIRED(&cdesc)) { 731 cdesc.afmt_ne = 732 (cdesc.dummy != 0) ? 733 snd_fmtbest(AFMT_ENCODING(softfmt), 734 feeder_chain_formats[cdesc.mode]) : 735 snd_fmtbest(AFMT_ENCODING(cdesc.target.afmt), 736 feeder_chain_formats[cdesc.mode]); 737 if (cdesc.afmt_ne == 0) { 738 device_printf(c->dev, 739 "%s(): snd_fmtbest failed!\n", __func__); 740 cdesc.afmt_ne = 741 (((cdesc.dummy != 0) ? softfmt : 742 cdesc.target.afmt) & 743 (AFMT_24BIT | AFMT_32BIT)) ? 744 AFMT_S32_NE : AFMT_S16_NE; 745 } 746 } 747 } 748 749 cdesc.current = cdesc.origin; 750 751 /* Build everything. */ 752 753 c->feederflags = 0; 754 755 #define FEEDER_BUILD(t) do { \ 756 ret = feeder_build_##t(c, &cdesc); \ 757 if (ret != 0) \ 758 return (ret); \ 759 } while (0) 760 761 if (!(c->flags & CHN_F_HAS_VCHAN) || c->direction == PCMDIR_REC) 762 FEEDER_BUILD(root); 763 else if (c->direction == PCMDIR_PLAY && (c->flags & CHN_F_HAS_VCHAN)) 764 FEEDER_BUILD(mixer); 765 else 766 return (ENOTSUP); 767 768 /* 769 * The basic idea is: The smaller the bandwidth, the cheaper the 770 * conversion process, with following constraints:- 771 * 772 * 1) Almost all feeders work best in 16/32 native endian. 773 * 2) Try to avoid 8bit feeders due to poor dynamic range. 774 * 3) Avoid volume, format, matrix and rate in BITPERFECT or 775 * PASSTHROUGH mode. 776 * 4) Try putting volume before EQ or rate. Should help to 777 * avoid/reduce possible clipping. 778 * 5) EQ require specific, valid rate, unless it allow sloppy 779 * conversion. 780 */ 781 if (FEEDMATRIX_UP(&cdesc)) { 782 if (FEEDEQ_REQUIRED(&cdesc) && 783 (!FEEDEQ_VALIDRATE(&cdesc, target) || 784 (cdesc.expensive == 0 && FEEDEQ_ECONOMY(&cdesc)))) 785 FEEDER_BUILD(eq); 786 if (FEEDRATE_REQUIRED(&cdesc)) 787 FEEDER_BUILD(rate); 788 FEEDER_BUILD(matrix); 789 if (FEEDVOLUME_REQUIRED(&cdesc)) 790 FEEDER_BUILD(volume); 791 if (FEEDEQ_REQUIRED(&cdesc)) 792 FEEDER_BUILD(eq); 793 } else if (FEEDMATRIX_DOWN(&cdesc)) { 794 FEEDER_BUILD(matrix); 795 if (FEEDVOLUME_REQUIRED(&cdesc)) 796 FEEDER_BUILD(volume); 797 if (FEEDEQ_REQUIRED(&cdesc) && 798 (!FEEDEQ_VALIDRATE(&cdesc, target) || 799 FEEDEQ_ECONOMY(&cdesc))) 800 FEEDER_BUILD(eq); 801 if (FEEDRATE_REQUIRED(&cdesc)) 802 FEEDER_BUILD(rate); 803 if (FEEDEQ_REQUIRED(&cdesc)) 804 FEEDER_BUILD(eq); 805 } else { 806 if (FEEDRATE_DOWN(&cdesc)) { 807 if (FEEDEQ_REQUIRED(&cdesc) && 808 !FEEDEQ_VALIDRATE(&cdesc, target)) { 809 if (FEEDVOLUME_REQUIRED(&cdesc)) 810 FEEDER_BUILD(volume); 811 FEEDER_BUILD(eq); 812 } 813 FEEDER_BUILD(rate); 814 } 815 if (FEEDMATRIX_REQUIRED(&cdesc)) 816 FEEDER_BUILD(matrix); 817 if (FEEDVOLUME_REQUIRED(&cdesc)) 818 FEEDER_BUILD(volume); 819 if (FEEDRATE_UP(&cdesc)) { 820 if (FEEDEQ_REQUIRED(&cdesc) && 821 !FEEDEQ_VALIDRATE(&cdesc, target)) 822 FEEDER_BUILD(eq); 823 FEEDER_BUILD(rate); 824 } 825 if (FEEDEQ_REQUIRED(&cdesc)) 826 FEEDER_BUILD(eq); 827 } 828 829 if (FEEDFORMAT_REQUIRED(&cdesc)) 830 FEEDER_BUILD(format); 831 832 if (c->direction == PCMDIR_REC && (c->flags & CHN_F_HAS_VCHAN)) 833 FEEDER_BUILD(mixer); 834 835 sndbuf_setfmt(c->bufsoft, c->format); 836 sndbuf_setspd(c->bufsoft, c->speed); 837 838 sndbuf_setfmt(c->bufhard, hwfmt); 839 840 chn_syncstate(c); 841 842 return (0); 843 } 844