Changeset 87942 in vbox
- Timestamp:
- Mar 3, 2021 5:26:37 PM (4 years ago)
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r87934 r87942 348 348 } 349 349 350 /* Assign the global device rate to the stream. */351 pStreamShared->State.uTimerIoHz = pThis->uTimerHz;352 353 /* Set scheduling hint (if available). */354 if (pStreamShared->State.uTimerIoHz)355 pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz;356 357 350 LogRel2(("HDA: Stream #%RU8 DMA @ 0x%x (%RU32 bytes = %RU64ms total)\n", 358 351 uSD, pStreamShared->u64BDLBase, pStreamShared->u32CBL, 359 DrvAudioHlpBytesToMilli(pStreamShared->u32CBL, &pStreamShared->State.Cfg.Props))); 360 361 /* Make sure that the chosen Hz rate dividable by the stream's rate. */ 362 if (pStreamShared->State.Cfg.Props.uHz % pStreamShared->State.uTimerIoHz != 0) 363 LogRel(("HDA: Stream #%RU8 timer Hz rate (%RU32) does not fit to stream #%RU8 timing (%RU32)\n", 364 uSD, pStreamShared->State.uTimerIoHz, uSD, pStreamShared->State.Cfg.Props.uHz)); 352 DrvAudioHlpBytesToMilli(pStreamShared->u32CBL, &pStreamR3->State.Mapping.PCMProps))); 365 353 366 354 /* Figure out how many transfer fragments we're going to use for this stream. */ … … 447 435 */ 448 436 449 /* Prevent division by zero. */ 450 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz, 451 ("Timer Hz rate for stream #%RU8 is invalid\n", uSD), 452 pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT); 437 /* Assign the global device rate to the stream I/O timer as default. */ 438 pStreamShared->State.uTimerIoHz = pThis->uTimerHz; 439 453 440 /* 454 441 * Determine the transfer Hz the guest OS expects data transfer at. … … 458 445 * 459 446 * Data rate examples: 460 * * Windows 10 @ 44,1kHz / 16-bit stereo 461 * * Default mode: 448 audio frames -> ~10.15ms) = 1792 byte every ~10ms. 462 * * Fast mode: 128 audio frames -> ~ 2.90ms) = 512 byte every ~3ms. 447 * * Windows 10 @ 44,1kHz / 16-bit 448 * 2 channels (stereo): 449 * * Default mode: 448 audio frames -> ~10.15ms = 1792 byte every ~10ms. 450 * * Fast mode: 128 audio frames -> ~ 2.90ms = 512 byte every ~3ms. 451 * 6 channels (5.1 surround): 452 * * Default mode: Same values as above! 463 453 */ 454 455 /* Audio data per second the stream needs. */ 456 const uint32_t cbDataPerSec = DrvAudioHlpMilliToBytes(RT_MS_1SEC, &pStreamR3->State.Mapping.PCMProps); 464 457 465 458 /* The transfer Hz depend on the heuristics above, that is, 466 459 how often the guest expects to see a new data transfer. */ 467 unsigned uTransferHz; 460 uint16_t uTransferHz = 0; 461 462 LogRel2(("HDA: Stream #%RU8 needs %RU32 bytes/s audio data\n", uSD, cbDataPerSec)); 468 463 469 464 if (pThis->fTransferHeuristicsEnabled) /* Are data transfer heuristics enabled? */ … … 483 478 PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd)); 484 479 480 LogRel2(("HDA: Stream #%RU8 BDLE #%RU8: %R[bdle]\n", uSD, i, &bd)); 481 485 482 /* Position adjustment (still) needed / active? */ 486 483 if (cbTransferHeuristicsPosAdjust) … … 510 507 511 508 /* Windows 10's audio driver expects a transfer all ~10.1ms (~1764 bytes), although 512 * it sets up 1792 bytes per BDLE. 509 * it sets up multiples of 1792 bytes (896 bytes per channel) per BDLE: 510 * 511 * * 2 (stereo) channels = 1792 512 * * 6 (surrounnd) channels = 1792 * 3 = 5376 513 * 514 * Same seems to apply to Windows 7 when using the default setup. 513 515 * 514 516 * I currently don't have any clue why it does this that way, so try to simply detect this 515 * and alter the value so that we get a somewhat proper audio output. */ 516 if (cbTransferHeuristicsMin == 1792) 517 { 518 LogRel2(("HDA: Guest seems to be Windows 10 -- setting a fixed transfer minimum size\n")); 517 * and alter the value so that we get a somewhat proper audio output. 518 * Probably alignment? 519 */ 520 if (cbTransferHeuristicsMin / (1792 / 2 /* Channels */) == pStreamR3->State.Mapping.PCMProps.cChannels) 521 { 522 LogRel2(("HDA: Heuristics detected a Windows guest -- setting a fixed transfer minimum size\n")); 519 523 cbTransferHeuristicsMin = 1764; 524 525 /* Anything above 5 channels (surround) will need higher timer rates -- otherwise it will be a lot worse. */ 526 if (pStreamR3->State.Mapping.PCMProps.cChannels >= 5) 527 { 528 uTransferHz = 100 + ((pStreamR3->State.Mapping.PCMProps.cChannels - 4) * 50); /* Add 50Hz per additional channel. */ 529 } 530 else /* Stick with 100Hz here. Anything lower will crackle. */ 531 uTransferHz = 100; 532 533 pStreamShared->State.uTimerIoHz = 50; 520 534 } 521 535 522 536 /* !!! HACK ALERT END !!! */ 523 537 524 uint32_t msTransferHeuristicsMin = DrvAudioHlpBytesToMilli(cbTransferHeuristicsMin, &pCfg->Props);525 526 /* Prevent division by zero. */527 ASSERT_GUEST_LOGREL_MSG_STMT(msTransferHeuristicsMin,528 ("Transfer heuristics for stream #%RU8 buggy\n", uSD), 529 msTransferHeuristicsMin = 10 /* ms, equals 100 Hz */);530 531 uTransferHz = RT_MS_1SEC / msTransferHeuristicsMin;532 533 LogRel2(("HDA: Stream #%RU8 needs a data transfer at least every %RU64ms (%RU32 bytes) -- transfers run at %uHz\n",534 uSD, msTransferHeuristicsMin,cbTransferHeuristicsMin, uTransferHz));535 } 536 else 537 { 538 /* Use I/Otiming rate instead. */539 uTransferHz = p StreamShared->State.uTimerIoHz;538 else 539 { 540 /* Calculate the transfer Hz rate by dividing the guessed transfer data rate by the data rate in ms. */ 541 uTransferHz = cbTransferHeuristicsMin / (cbDataPerSec / RT_MS_1SEC); 542 543 /* Make sure that the timer I/O Hz rate is the same in this case, as we can't do any more guessing here. */ 544 pStreamShared->State.uTimerIoHz = uTransferHz; 545 } 546 547 LogRel2(("HDA: Stream #%RU8 seems to need a transfer worth of %RU32 bytes audio data, so trying to run transfers at %uHz\n", 548 uSD, cbTransferHeuristicsMin, uTransferHz)); 549 } 550 else /* Heuristics disabled. */ 551 { 552 /* Use global timing rate instead. */ 553 uTransferHz = pThis->uTimerHz; 540 554 } 541 555 542 556 if (uTransferHz > 400) /* Anything above 400 Hz looks fishy -- tell the user. */ 543 LogRel(("HDA: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), please re-run with audio debug mode and report a bug\n", 557 LogRel(("HDA: Warning: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), " 558 "please re-run with audio debug mode and report a bug\n", 544 559 uSD, uTransferHz)); 545 560 561 LogRel2(("HDA: Stream #%RU8 transfer timer rate is %RU16Hz, I/O timer rate is %RU16Hz\n", 562 uSD, uTransferHz, pStreamShared->State.uTimerIoHz)); 563 564 /* Make sure that the chosen transfer Hz rate dividable by the stream's overall data rate. */ 565 ASSERT_GUEST_LOGREL_MSG_STMT(cbDataPerSec % uTransferHz == 0, 566 ("Transfer data rate (%RU32 bytes/s) for stream #%RU8 does not fit to stream timing (%RU32Hz)\n", 567 cbDataPerSec, uSD, uTransferHz), 568 uTransferHz = HDA_TIMER_HZ_DEFAULT); 569 570 /* Prevent division by zero. */ 571 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz, 572 ("I/O timer Hz rate for stream #%RU8 is invalid\n", uSD), 573 pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT); 574 575 /* Set I/O scheduling hint for the backends. */ 576 pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz; 577 LogRel2(("HDA: Stream #%RU8 set scheduling hint for the backends to %RU32ms\n", uSD, pCfg->Device.cMsSchedulingHint)); 578 546 579 pStreamShared->State.cbTransferSize = 547 (pStream Shared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize) / uTransferHz;580 (pStreamR3->State.Mapping.PCMProps.uHz * pStreamR3->State.Mapping.cbFrameSize) / 100 /* Hz */; 548 581 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize, 549 582 ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER); 583 550 584 if (RT_SUCCESS(rc)) 551 585 { … … 568 602 const uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer); 569 603 570 const double cTicksPerHz = uTimerFreq / pStreamShared->State.uTimerIoHz;604 const double cTicksPerHz = uTimerFreq / uTransferHz; 571 605 double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk; 572 606 573 if ( pStreamShared->State.uTimerIoHz < uTransferHz)574 cTicksPerByte /= uTransferHz / pStreamShared->State.uTimerIoHz;607 if (uTransferHz < 100) 608 cTicksPerByte /= 100 / uTransferHz; 575 609 else 576 cTicksPerByte *= pStreamShared->State.uTimerIoHz / uTransferHz;610 cTicksPerByte *= uTransferHz / 100; 577 611 578 612 Assert(cTicksPerByte); … … 594 628 LogRel2(("HDA: Stream #%RU8 is using %uHz I/O timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, " 595 629 "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n", 596 uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStream Shared->State.Cfg.Props.uHz,630 uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamR3->State.Mapping.PCMProps.uHz, 597 631 pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks, 598 pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &p Cfg->Props),599 pStreamShared->State.cbTransferSize, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize, &p Cfg->Props)));632 pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pStreamR3->State.Mapping.PCMProps), 633 pStreamShared->State.cbTransferSize, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize, &pStreamR3->State.Mapping.PCMProps))); 600 634 601 635 /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */ … … 630 664 const unsigned uTransferHzMin = RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz); 631 665 666 /* Note: Use pCfg->Props as PCM properties here, as we only want to store the samples we actually need, 667 * in other words, skipping the interleaved channels we don't support / need to save space. */ 668 632 669 uint32_t cbCircBuf; 633 670 const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes((RT_MS_1SEC / uTransferHzMin) * 3, &pCfg->Props); … … 640 677 if (cbCircBufGlobal) /* Anything set via CFGM? */ 641 678 { 642 643 ASSERT_GUEST_LOGREL_MSG_STMT(DrvAudioHlpBytesIsAligned(cbCircBufGlobal, &pCfg->Props),644 ("Ring buffer size for stream #%RU8 is misaligned (%zu), setting to default\n", uSD, cbCircBufGlobal),645 cbCircBufGlobal = cbCircBufDefault);646 647 679 LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU64ms (%RU32 bytes)\n", 648 680 uSD, DrvAudioHlpBytesToMilli(cbCircBufGlobal, &pCfg->Props), cbCircBufGlobal)); … … 652 684 else 653 685 cbCircBuf = cbCircBufDefault; 686 687 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf % (pCfg->Props.cbSample * pCfg->Props.cChannels) == 0, 688 ("Ring buffer size (%RU32) for stream #%RU8 not aligned to mapping's frame size (%RU8)\n", 689 cbCircBuf, uSD, pCfg->Props.cbSample * pCfg->Props.cChannels), 690 rc = VERR_INVALID_PARAMETER); 654 691 655 692 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf, … … 1680 1717 uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable); 1681 1718 /* Make sure that we always align the number of bytes when reading to the stream's PCM properties. */ 1682 cbToReadFromStream = DrvAudioHlpBytesAlign(cbToReadFromStream, &pStream Shared->State.Cfg.Props);1719 cbToReadFromStream = DrvAudioHlpBytesAlign(cbToReadFromStream, &pStreamR3->State.Mapping.PCMProps); 1683 1720 1684 1721 #ifdef LOG_ENABLED -
trunk/src/VBox/Devices/Audio/HDAStreamMap.cpp
r82968 r87942 123 123 pMap->cMappings = 0; 124 124 } 125 126 RT_ZERO(pMap->PCMProps); 125 127 } 126 128 … … 165 167 rc = hdaR3StreamChannelDataInit(&pMapLR->Data, PDMAUDIOSTREAMCHANNELDATA_FLAGS_NONE); 166 168 AssertRC(rc); 169 170 memcpy(&pMap->PCMProps, pProps, sizeof(PDMAUDIOPCMPROPS)); 167 171 } 168 172 else -
trunk/src/VBox/Devices/Audio/HDAStreamMap.h
r82968 r87942 27 27 typedef struct HDASTREAMMAP 28 28 { 29 /** The PCM properties which have been used. */ 30 PDMAUDIOPCMPROPS PCMProps; 29 31 /** The stream's layout. */ 30 32 PDMAUDIOSTREAMLAYOUT enmLayout; 33 /** The mapping's overall audio frame size (in bytes). 34 * This includes all mappings in \a paMappings. */ 31 35 uint8_t cbFrameSize; 32 36 /** Number of mappings in paMappings. */
Note:
See TracChangeset
for help on using the changeset viewer.