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 35SND_DECLARE_FILE("$FreeBSD: releng/10.3/sys/dev/sound/pcm/feeder_chain.c 283950 2015-06-03 15:32:43Z hselasky $"); 36 37/* chain state */ 38struct 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 */ 48struct 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. */ 83static 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. */ 89static uint32_t feeder_chain_formats_16[] = { 90 AFMT_S16_NE, 91 0 92}; 93 94/* Force everything to signed 32 bit native endian. */ 95static uint32_t feeder_chain_formats_32[] = { 96 AFMT_S32_NE, 97 0 98}; 99 100/* Multiple choices, all except 8 bit. */ 101static 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. */ 109static 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 117static 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 125static int feeder_chain_mode = FEEDER_CHAIN_DEFAULT; 126 127#if defined(_KERNEL) && defined(SND_DEBUG) && defined(SND_FEEDER_FULL_MULTIFORMAT) 128TUNABLE_INT("hw.snd.feeder_chain_mode", &feeder_chain_mode); 129SYSCTL_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 */ 138static int 139feeder_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 */ 179static int 180feeder_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 */ 206static int 207feeder_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 */ 284static int 285feeder_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 */ 341static int 342feeder_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 */ 409static int 410feeder_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 */ 463static int 464feeder_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 */ 494static int 495feeder_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 565static void 566feeder_default_matrix(struct pcmchan_matrix *m, uint32_t fmt, int id) 567{ 568 int x; 569 570 memset(m, 0, sizeof(*m)); 571 572 m->id = id; 573 m->channels = AFMT_CHANNEL(fmt); 574 m->ext = AFMT_EXTCHANNEL(fmt); 575 for (x = 0; x != SND_CHN_T_MAX; x++) 576 m->offset[x] = -1; 577} 578 579int 580feeder_chain(struct pcm_channel *c) 581{ 582 struct snddev_info *d; 583 struct pcmchan_caps *caps; 584 struct feeder_chain_desc cdesc; 585 struct pcmchan_matrix *hwmatrix, *softmatrix; 586 uint32_t hwfmt, softfmt; 587 int ret; 588 589 CHN_LOCKASSERT(c); 590 591 /* Remove everything first. */ 592 while (chn_removefeeder(c) == 0) 593 ; 594 595 KASSERT(c->feeder == NULL, ("feeder chain not empty")); 596 597 /* clear and populate chain descriptor. */ 598 bzero(&cdesc, sizeof(cdesc)); 599 600 switch (feeder_chain_mode) { 601 case FEEDER_CHAIN_LEAN: 602 case FEEDER_CHAIN_16: 603 case FEEDER_CHAIN_32: 604#if defined(SND_FEEDER_MULTIFORMAT) || defined(SND_FEEDER_FULL_MULTIFORMAT) 605 case FEEDER_CHAIN_MULTI: 606#endif 607#if defined(SND_FEEDER_FULL_MULTIFORMAT) 608 case FEEDER_CHAIN_FULLMULTI: 609#endif 610 break; 611 default: 612 feeder_chain_mode = FEEDER_CHAIN_DEFAULT; 613 break; 614 } 615 616 cdesc.mode = feeder_chain_mode; 617 cdesc.expensive = 1; /* XXX faster.. */ 618 619#define VCHAN_PASSTHROUGH(c) (((c)->flags & (CHN_F_VIRTUAL | \ 620 CHN_F_PASSTHROUGH)) == \ 621 (CHN_F_VIRTUAL | CHN_F_PASSTHROUGH)) 622 623 /* Get the best possible hardware format. */ 624 if (VCHAN_PASSTHROUGH(c)) 625 hwfmt = c->parentchannel->format; 626 else { 627 caps = chn_getcaps(c); 628 if (caps == NULL || caps->fmtlist == NULL) { 629 device_printf(c->dev, 630 "%s(): failed to get channel caps\n", __func__); 631 return (ENODEV); 632 } 633 634 if ((c->format & AFMT_PASSTHROUGH) && 635 !snd_fmtvalid(c->format, caps->fmtlist)) 636 return (ENODEV); 637 638 hwfmt = snd_fmtbest(c->format, caps->fmtlist); 639 if (hwfmt == 0 || !snd_fmtvalid(hwfmt, caps->fmtlist)) { 640 device_printf(c->dev, 641 "%s(): invalid hardware format 0x%08x\n", 642 __func__, hwfmt); 643 { 644 int i; 645 for (i = 0; caps->fmtlist[i] != 0; i++) 646 printf("0x%08x\n", caps->fmtlist[i]); 647 printf("Req: 0x%08x\n", c->format); 648 } 649 return (ENODEV); 650 } 651 } 652 653 /* 654 * The 'hardware' possibly have different intepretation of channel 655 * matrixing, so get it first ..... 656 */ 657 hwmatrix = CHANNEL_GETMATRIX(c->methods, c->devinfo, hwfmt); 658 if (hwmatrix == NULL) { 659 /* setup a default matrix */ 660 hwmatrix = &c->matrix_scratch; 661 feeder_default_matrix(hwmatrix, hwfmt, 662 SND_CHN_MATRIX_UNKNOWN); 663 } 664 /* ..... and rebuild hwfmt. */ 665 hwfmt = SND_FORMAT(hwfmt, hwmatrix->channels, hwmatrix->ext); 666 667 /* Reset and rebuild default channel format/matrix map. */ 668 softfmt = c->format; 669 softmatrix = &c->matrix; 670 if (softmatrix->channels != AFMT_CHANNEL(softfmt) || 671 softmatrix->ext != AFMT_EXTCHANNEL(softfmt)) { 672 softmatrix = feeder_matrix_format_map(softfmt); 673 if (softmatrix == NULL) { 674 /* setup a default matrix */ 675 softmatrix = &c->matrix; 676 feeder_default_matrix(softmatrix, softfmt, 677 SND_CHN_MATRIX_PCMCHANNEL); 678 } else { 679 c->matrix = *softmatrix; 680 c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL; 681 } 682 } 683 softfmt = SND_FORMAT(softfmt, softmatrix->channels, softmatrix->ext); 684 if (softfmt != c->format) 685 device_printf(c->dev, 686 "%s(): WARNING: %s Soft format 0x%08x -> 0x%08x\n", 687 __func__, CHN_DIRSTR(c), c->format, softfmt); 688 689 /* 690 * PLAY and REC are opposite. 691 */ 692 if (c->direction == PCMDIR_PLAY) { 693 cdesc.origin.afmt = softfmt; 694 cdesc.origin.matrix = softmatrix; 695 cdesc.origin.rate = c->speed; 696 cdesc.target.afmt = hwfmt; 697 cdesc.target.matrix = hwmatrix; 698 cdesc.target.rate = sndbuf_getspd(c->bufhard); 699 } else { 700 cdesc.origin.afmt = hwfmt; 701 cdesc.origin.matrix = hwmatrix; 702 cdesc.origin.rate = sndbuf_getspd(c->bufhard); 703 cdesc.target.afmt = softfmt; 704 cdesc.target.matrix = softmatrix; 705 cdesc.target.rate = c->speed; 706 } 707 708 d = c->parentsnddev; 709 710 /* 711 * If channel is in bitperfect or passthrough mode, make it appear 712 * that 'origin' and 'target' identical, skipping mostly chain 713 * procedures. 714 */ 715 if (CHN_BITPERFECT(c) || (c->format & AFMT_PASSTHROUGH)) { 716 if (c->direction == PCMDIR_PLAY) 717 cdesc.origin = cdesc.target; 718 else 719 cdesc.target = cdesc.origin; 720 c->format = cdesc.target.afmt; 721 c->speed = cdesc.target.rate; 722 } else { 723 /* hwfmt is not convertible, so 'dummy' it. */ 724 if (hwfmt & AFMT_PASSTHROUGH) 725 cdesc.dummy = 1; 726 727 if ((softfmt & AFMT_CONVERTIBLE) && 728 (((d->flags & SD_F_VPC) && !(c->flags & CHN_F_HAS_VCHAN)) || 729 (!(d->flags & SD_F_VPC) && (d->flags & SD_F_SOFTPCMVOL) && 730 !(c->flags & CHN_F_VIRTUAL)))) 731 cdesc.use_volume = 1; 732 733 if (feeder_matrix_compare(cdesc.origin.matrix, 734 cdesc.target.matrix) != 0) 735 cdesc.use_matrix = 1; 736 737 /* Soft EQ only applicable for PLAY. */ 738 if (cdesc.dummy == 0 && 739 c->direction == PCMDIR_PLAY && (d->flags & SD_F_EQ) && 740 (((d->flags & SD_F_EQ_PC) && 741 !(c->flags & CHN_F_HAS_VCHAN)) || 742 (!(d->flags & SD_F_EQ_PC) && !(c->flags & CHN_F_VIRTUAL)))) 743 cdesc.use_eq = 1; 744 745 if (FEEDFORMAT_NE_REQUIRED(&cdesc)) { 746 cdesc.afmt_ne = 747 (cdesc.dummy != 0) ? 748 snd_fmtbest(AFMT_ENCODING(softfmt), 749 feeder_chain_formats[cdesc.mode]) : 750 snd_fmtbest(AFMT_ENCODING(cdesc.target.afmt), 751 feeder_chain_formats[cdesc.mode]); 752 if (cdesc.afmt_ne == 0) { 753 device_printf(c->dev, 754 "%s(): snd_fmtbest failed!\n", __func__); 755 cdesc.afmt_ne = 756 (((cdesc.dummy != 0) ? softfmt : 757 cdesc.target.afmt) & 758 (AFMT_24BIT | AFMT_32BIT)) ? 759 AFMT_S32_NE : AFMT_S16_NE; 760 } 761 } 762 } 763 764 cdesc.current = cdesc.origin; 765 766 /* Build everything. */ 767 768 c->feederflags = 0; 769 770#define FEEDER_BUILD(t) do { \ 771 ret = feeder_build_##t(c, &cdesc); \ 772 if (ret != 0) \ 773 return (ret); \ 774 } while (0) 775 776 if (!(c->flags & CHN_F_HAS_VCHAN) || c->direction == PCMDIR_REC) 777 FEEDER_BUILD(root); 778 else if (c->direction == PCMDIR_PLAY && (c->flags & CHN_F_HAS_VCHAN)) 779 FEEDER_BUILD(mixer); 780 else 781 return (ENOTSUP); 782 783 /* 784 * The basic idea is: The smaller the bandwidth, the cheaper the 785 * conversion process, with following constraints:- 786 * 787 * 1) Almost all feeders work best in 16/32 native endian. 788 * 2) Try to avoid 8bit feeders due to poor dynamic range. 789 * 3) Avoid volume, format, matrix and rate in BITPERFECT or 790 * PASSTHROUGH mode. 791 * 4) Try putting volume before EQ or rate. Should help to 792 * avoid/reduce possible clipping. 793 * 5) EQ require specific, valid rate, unless it allow sloppy 794 * conversion. 795 */ 796 if (FEEDMATRIX_UP(&cdesc)) { 797 if (FEEDEQ_REQUIRED(&cdesc) && 798 (!FEEDEQ_VALIDRATE(&cdesc, target) || 799 (cdesc.expensive == 0 && FEEDEQ_ECONOMY(&cdesc)))) 800 FEEDER_BUILD(eq); 801 if (FEEDRATE_REQUIRED(&cdesc)) 802 FEEDER_BUILD(rate); 803 FEEDER_BUILD(matrix); 804 if (FEEDVOLUME_REQUIRED(&cdesc)) 805 FEEDER_BUILD(volume); 806 if (FEEDEQ_REQUIRED(&cdesc)) 807 FEEDER_BUILD(eq); 808 } else if (FEEDMATRIX_DOWN(&cdesc)) { 809 FEEDER_BUILD(matrix); 810 if (FEEDVOLUME_REQUIRED(&cdesc)) 811 FEEDER_BUILD(volume); 812 if (FEEDEQ_REQUIRED(&cdesc) && 813 (!FEEDEQ_VALIDRATE(&cdesc, target) || 814 FEEDEQ_ECONOMY(&cdesc))) 815 FEEDER_BUILD(eq); 816 if (FEEDRATE_REQUIRED(&cdesc)) 817 FEEDER_BUILD(rate); 818 if (FEEDEQ_REQUIRED(&cdesc)) 819 FEEDER_BUILD(eq); 820 } else { 821 if (FEEDRATE_DOWN(&cdesc)) { 822 if (FEEDEQ_REQUIRED(&cdesc) && 823 !FEEDEQ_VALIDRATE(&cdesc, target)) { 824 if (FEEDVOLUME_REQUIRED(&cdesc)) 825 FEEDER_BUILD(volume); 826 FEEDER_BUILD(eq); 827 } 828 FEEDER_BUILD(rate); 829 } 830 if (FEEDMATRIX_REQUIRED(&cdesc)) 831 FEEDER_BUILD(matrix); 832 if (FEEDVOLUME_REQUIRED(&cdesc)) 833 FEEDER_BUILD(volume); 834 if (FEEDRATE_UP(&cdesc)) { 835 if (FEEDEQ_REQUIRED(&cdesc) && 836 !FEEDEQ_VALIDRATE(&cdesc, target)) 837 FEEDER_BUILD(eq); 838 FEEDER_BUILD(rate); 839 } 840 if (FEEDEQ_REQUIRED(&cdesc)) 841 FEEDER_BUILD(eq); 842 } 843 844 if (FEEDFORMAT_REQUIRED(&cdesc)) 845 FEEDER_BUILD(format); 846 847 if (c->direction == PCMDIR_REC && (c->flags & CHN_F_HAS_VCHAN)) 848 FEEDER_BUILD(mixer); 849 850 sndbuf_setfmt(c->bufsoft, c->format); 851 sndbuf_setspd(c->bufsoft, c->speed); 852 853 sndbuf_setfmt(c->bufhard, hwfmt); 854 855 chn_syncstate(c); 856 857 return (0); 858} 859