Changeset 87758 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Feb 15, 2021 12:14:09 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 142810
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r87573 r87758 1442 1442 */ 1443 1443 uint64_t cTicksToNext = pStreamShared->State.cTransferTicks; 1444 Assert(cTicksToNext == cTicksToNext);1445 1444 if (cTicksToNext) /* Only do any calculations if the stream currently is set up for transfers. */ 1446 1445 { … … 1860 1859 static VBOXSTRICTRC hdaRegWriteSDFMT(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 1861 1860 { 1861 #ifdef IN_RING3 1862 PDMAUDIOPCMPROPS Props; 1863 int rc2 = hdaR3SDFMTToPCMProps(RT_LO_U16(u32Value), &Props); 1864 AssertRC(rc2); 1865 LogFunc(("[SD%RU8] Set to %#x (%RU32Hz, %RU8bit, %RU8 channel(s))\n", 1866 HDA_SD_NUM_FROM_REG(pThis, FMT, iReg), u32Value, Props.uHz, Props.cbSample * 8 /* Bit */, Props.cChannels)); 1867 1862 1868 /* 1863 1869 * Write the wanted stream format into the register in any case. … … 1870 1876 */ 1871 1877 return hdaRegWriteU16(pDevIns, pThis, iReg, u32Value); 1878 #else 1879 RT_NOREF(pDevIns, pThis, iReg, u32Value); 1880 return VINF_IOM_R3_MMIO_WRITE; 1881 #endif 1872 1882 } 1873 1883 … … 2654 2664 fSinkActive = AudioMixerSinkIsActive(pStreamR3->pMixSink->pMixSink); 2655 2665 2666 #ifdef LOG_ENABLED 2667 const uint8_t uSD = pStreamShared->u8SD; 2668 #endif 2669 2656 2670 if (fSinkActive) 2657 2671 { 2658 uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, hTimer); /* (For virtual sync this remains the same for the whole callout IIRC) */ 2659 const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow); 2660 Log3Func(("fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", fSinkActive, fTimerScheduled)); 2672 const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, hTimer); /* (For virtual sync this remains the same for the whole callout IIRC) */ 2673 const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow); 2674 2675 Log3Func(("[SD%RU8] fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", uSD, fSinkActive, fTimerScheduled)); 2676 2661 2677 if (!fTimerScheduled) 2662 hdaR3TimerSet(pDevIns, pStreamShared, tsNow + PDMDevHlpTimerGetFreq(pDevIns, hTimer) / pThis->uTimerHz, 2663 true /*fForce*/, tsNow /*fixed*/ ); 2678 { 2679 if (!pStreamShared->State.tsTransferLast) /* Never did a transfer before? Initialize with current time. */ 2680 pStreamShared->State.tsTransferLast = tsNow; 2681 2682 Assert(tsNow >= pStreamShared->State.tsTransferLast); 2683 2684 /* How many ticks have passed since the last transfer? */ 2685 const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast; 2686 2687 uint64_t cTicksToNext; 2688 if (cTicksElapsed == 0) /* We just ran in the same timing slot? */ 2689 { 2690 /* Schedule a transfer at the next regular timing slot. */ 2691 cTicksToNext = pStreamShared->State.cTransferTicks; 2692 } 2693 else 2694 { 2695 /* Some time since the last transfer has passed already; take this into account. */ 2696 if (pStreamShared->State.cTransferTicks >= cTicksElapsed) 2697 { 2698 cTicksToNext = pStreamShared->State.cTransferTicks - cTicksElapsed; 2699 } 2700 else /* Catch up as soon as possible. */ 2701 cTicksToNext = 0; 2702 } 2703 2704 Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferLast=%RU64, cTicksElapsed=%RU64 -> cTicksToNext=%RU64\n", 2705 uSD, tsNow, pStreamShared->State.tsTransferLast, cTicksElapsed, cTicksToNext)); 2706 2707 /* Note: cTicksToNext can be 0, which means we have to run *now*. */ 2708 hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext, 2709 true /*fForce*/, 0 /* tsNow */); 2710 } 2664 2711 } 2665 2712 else 2666 Log3Func((" fSinksActive=%RTbool\n", fSinkActive));2713 Log3Func(("[SD%RU8] fSinksActive=%RTbool\n", uSD, fSinkActive)); 2667 2714 } 2668 2715 … … 4588 4635 * Validate and read configuration. 4589 4636 */ 4590 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|TimerHz|PosAdjustEnabled|PosAdjustFrames| DebugEnabled|DebugPathOut", "");4637 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|TimerHz|PosAdjustEnabled|PosAdjustFrames|TransferHeuristicsEnabled|DebugEnabled|DebugPathOut", ""); 4591 4638 4592 4639 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */ 4593 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, RT_MS_10SEC/* Default value, if not set. */);4640 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, 0 /* Default value, if not set. */); 4594 4641 if (RT_FAILURE(rc)) 4595 4642 return PDMDEV_SET_ERROR(pDevIns, rc, … … 4597 4644 4598 4645 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */ 4599 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, RT_MS_10SEC/* Default value, if not set. */);4646 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, 0 /* Default value, if not set. */); 4600 4647 if (RT_FAILURE(rc)) 4601 4648 return PDMDEV_SET_ERROR(pDevIns, rc, … … 4625 4672 if (pThis->cPosAdjustFrames) 4626 4673 LogRel(("HDA: Using custom position adjustment (%RU16 audio frames)\n", pThis->cPosAdjustFrames)); 4674 4675 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TransferHeuristicsEnabled", &pThis->fTransferHeuristicsEnabled, true); 4676 if (RT_FAILURE(rc)) 4677 return PDMDEV_SET_ERROR(pDevIns, rc, 4678 N_("HDA configuration error: failed to read data transfer heuristics enabled as boolean")); 4679 4680 if (!pThis->fTransferHeuristicsEnabled) 4681 LogRel(("HDA: Data transfer heuristics are disabled\n")); 4627 4682 4628 4683 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false); -
trunk/src/VBox/Devices/Audio/DevHDA.h
r87567 r87758 112 112 /** Whether the position adjustment is enabled or not. */ 113 113 bool fPosAdjustEnabled; 114 /** Whether data transfer heuristics are enabled or not. 115 * This tries to determine the approx. data rate a guest audio driver expects. */ 116 bool fTransferHeuristicsEnabled; 114 117 /** DMA position buffer enable bit. */ 115 118 bool fDMAPosition; -
trunk/src/VBox/Devices/Audio/DevHDACommon.h
r87573 r87758 108 108 /** Default timer frequency (in Hz). 109 109 * 110 * Lowering this value can ask for trouble, as backends then can run 111 * into data underruns. 112 * 113 * Note: For handling surround setups (e.g. 5.1 speaker setups) we need 114 * a higher Hz rate, as the device emulation otherwise will come into 115 * timing trouble, making the output (DMA reads) crackling. */ 110 * 20 Hz now seems enough for most setups, even with load on the guest. 111 * Raising the rate will produce more I/O load on the guest and therefore 112 * also will affect the performance. 113 */ 116 114 #define HDA_TIMER_HZ_DEFAULT 100 117 115 -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r87586 r87758 3197 3197 if (!pCfgReq->Backend.cFramesPeriod) /* Set default period size if nothing explicitly is set. */ 3198 3198 { 3199 pCfgReq->Backend.cFramesPeriod = DrvAudioHlpMilliToFrames( 50 /* ms */, &pCfgReq->Props);3199 pCfgReq->Backend.cFramesPeriod = DrvAudioHlpMilliToFrames(150 /* ms */, &pCfgReq->Props); 3200 3200 RTStrPrintf(szWhat, sizeof(szWhat), "default"); 3201 3201 } … … 3216 3216 if (!pCfgReq->Backend.cFramesBufferSize) /* Set default buffer size if nothing explicitly is set. */ 3217 3217 { 3218 pCfgReq->Backend.cFramesBufferSize = DrvAudioHlpMilliToFrames( 250 /* ms */, &pCfgReq->Props);3218 pCfgReq->Backend.cFramesBufferSize = DrvAudioHlpMilliToFrames(300 /* ms */, &pCfgReq->Props); 3219 3219 RTStrPrintf(szWhat, sizeof(szWhat), "default"); 3220 3220 } -
trunk/src/VBox/Devices/Audio/HDACodec.cpp
r82968 r87758 947 947 { 948 948 pNode->afg.node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd); 949 /* We set the AFG's PCM capabitilies fixed to 44.1kHz, 16-bit signed. */950 pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_ 16_BIT;949 /* We set the AFG's PCM capabitilies fixed to 16kHz, 22.5kHz + 44.1kHz, 16-bit signed. */ 950 pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_44_1KHZ_1_2X | CODEC_F00_0A_48KHZ_1_3X | CODEC_F00_0A_16_BIT; 951 951 pNode->afg.node.au32F00_param[0x0B] = CODEC_F00_0B_PCM; 952 952 pNode->afg.node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17) … … 990 990 { 991 991 pNode->dac.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ, 992 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_ 1X, HDA_SDFMT_16_BIT,992 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT, 993 993 HDA_SDFMT_CHAN_STEREO); 994 994 … … 1029 1029 1030 1030 pNode->adc.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ, 1031 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_ 1X, HDA_SDFMT_16_BIT,1031 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT, 1032 1032 HDA_SDFMT_CHAN_STEREO); 1033 1033 … … 1051 1051 { 1052 1052 pNode->spdifout.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ, 1053 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_ 1X, HDA_SDFMT_16_BIT,1053 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT, 1054 1054 HDA_SDFMT_CHAN_STEREO); 1055 1055 pNode->spdifout.u32F06_param = 0; … … 1070 1070 { 1071 1071 pNode->spdifin.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ, 1072 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_ 1X, HDA_SDFMT_16_BIT,1072 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT, 1073 1073 HDA_SDFMT_CHAN_STEREO); 1074 1074 -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r87638 r87758 301 301 #endif 302 302 303 /*304 * Set the stream's timer Hz rate, based on the stream channel count.305 * Currently this is just a rough guess and we might want to optimize this further.306 *307 * In any case, more channels per SDI/SDO means that we have to drive data more frequently.308 */309 if (pThis->uTimerHz == HDA_TIMER_HZ_DEFAULT) /* Make sure that we don't have any custom Hz rate set we want to enforce */310 {311 if (Props.cChannels >= 5)312 pStreamShared->State.uTimerHz = 300;313 else if (Props.cChannels == 4)314 pStreamShared->State.uTimerHz = 150;315 else316 pStreamShared->State.uTimerHz = 100;317 }318 else319 pStreamShared->State.uTimerHz = pThis->uTimerHz;320 321 /* Did some of the vital / critical parameters change?322 * If not, we can skip a lot of the (re-)initialization and just (re-)use the existing stuff.323 * Also, tell the caller so that further actions can be taken. */324 if ( uSD == pStreamShared->u8SD /* paranoia OFC */325 && u64BDLBase == pStreamShared->u64BDLBase326 && u16LVI == pStreamShared->u16LVI327 && u32CBL == pStreamShared->u32CBL328 && u8FIFOS == pStreamShared->u8FIFOS329 && u8FIFOW == pStreamShared->u8FIFOW330 && u16FMT == pStreamShared->u16FMT)331 {332 LogFunc(("[SD%RU8] No format change, skipping (re-)initialization\n", uSD));333 return VINF_NO_CHANGE;334 }335 336 303 /* Make sure the guest behaves regarding the stream's FIFO. */ 337 304 ASSERT_GUEST_LOGREL_MSG_STMT(u8FIFOW <= u8FIFOS, … … 351 318 PPDMAUDIOSTREAMCFG pCfg = &pStreamShared->State.Cfg; 352 319 pCfg->Props = Props; 353 354 /* (Re-)Allocate the stream's internal DMA buffer, based on the PCM properties we just got above. */355 if (pStreamR3->State.pCircBuf)356 {357 RTCircBufDestroy(pStreamR3->State.pCircBuf);358 pStreamR3->State.pCircBuf = NULL;359 }360 361 const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes(RT_MS_10SEC, &pCfg->Props);362 363 uint32_t cbCircBuf = DrvAudioHlpMilliToBytes( hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN364 ? pThis->cbCircBufInMs : pThis->cbCircBufOutMs, &pCfg->Props);365 366 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf,367 ("Ring buffer size for stream #%RU8 is invalid (%zu), setting to default\n", uSD, cbCircBuf),368 cbCircBuf = cbCircBufDefault);369 ASSERT_GUEST_LOGREL_MSG_STMT(DrvAudioHlpBytesIsAligned(cbCircBuf, &pCfg->Props),370 ("Ring buffer size for stream #%RU8 is misaligned (%zu), setting to default\n", uSD, cbCircBuf),371 cbCircBuf = cbCircBufDefault);372 373 if (cbCircBuf != cbCircBufDefault)374 LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU64ms (%RU32 bytes)\n",375 uSD, DrvAudioHlpBytesToMilli(cbCircBuf, &pCfg->Props), cbCircBuf));376 377 rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBuf);378 AssertRCReturn(rc, rc);379 320 380 321 /* Set the stream's direction. */ … … 400 341 401 342 default: 402 rc = VERR_NOT_SUPPORTED;343 AssertFailedReturn(VERR_NOT_SUPPORTED); 403 344 break; 404 345 } 405 346 347 /* Assign the global device rate to the stream. */ 348 pStreamShared->State.uTimerIoHz = pThis->uTimerHz; 349 406 350 /* Set scheduling hint (if available). */ 407 if (pStreamShared->State.uTimerHz) 408 pCfg->Device.cMsSchedulingHint = 1000 /* ms */ / pStreamShared->State.uTimerHz; 409 410 LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU8\n", 411 uSD, pStreamShared->u64BDLBase, pStreamShared->u32CBL, pStreamShared->u16LVI, pStreamShared->u8FIFOS)); 412 351 if (pStreamShared->State.uTimerIoHz) 352 pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz; 353 354 LogRel2(("HDA: Stream #%RU8 DMA @ 0x%x (%RU32 bytes = %RU64ms total)\n", 355 uSD, pStreamShared->u64BDLBase, pStreamShared->u32CBL, 356 DrvAudioHlpBytesToMilli(pStreamShared->u32CBL, &pStreamShared->State.Cfg.Props))); 357 358 /* Make sure that the chosen Hz rate dividable by the stream's rate. */ 359 if (pStreamShared->State.Cfg.Props.uHz % pStreamShared->State.uTimerIoHz != 0) 360 LogRel(("HDA: Stream #%RU8 timer Hz rate (%RU32) does not fit to stream #%RU8 timing (%RU32)\n", 361 uSD, pStreamShared->State.uTimerIoHz, uSD, pStreamShared->State.Cfg.Props.uHz)); 362 363 /* Figure out how many transfer fragments we're going to use for this stream. */ 364 uint8_t cTransferFragments = pStreamShared->u16LVI + 1; 365 if (cTransferFragments <= 1) 366 LogRel(("HDA: Warning: Stream #%RU8 transfer fragments (%RU8) invalid -- buggy guest audio driver!\n", 367 uSD, pStreamShared->u16LVI)); 368 369 /* 370 * Handle the stream's position adjustment. 371 */ 372 uint32_t cfPosAdjust = 0; 373 374 LogFunc(("[SD%RU8] fPosAdjustEnabled=%RTbool, cPosAdjustFrames=%RU16\n", 375 uSD, pThis->fPosAdjustEnabled, pThis->cPosAdjustFrames)); 376 377 if (pThis->fPosAdjustEnabled) /* Is the position adjustment enabled at all? */ 378 { 379 HDABDLE BDLE; 380 RT_ZERO(BDLE); 381 382 int rc2 = hdaR3BDLEFetch(pDevIns, &BDLE, pStreamShared->u64BDLBase, 0 /* Entry */); 383 AssertRC(rc2); 384 385 /* Note: Do *not* check if this BDLE aligns to the stream's frame size. 386 * It can happen that this isn't the case on some guests, e.g. 387 * on Windows with a 5.1 speaker setup. 388 * 389 * The only thing which counts is that the stream's CBL value 390 * properly aligns to the stream's frame size. 391 */ 392 393 /* If no custom set position adjustment is set, apply some 394 * simple heuristics to detect the appropriate position adjustment. */ 395 if ( !pThis->cPosAdjustFrames 396 /* Position adjustmenet buffer *must* have the IOC bit set! */ 397 && hdaR3BDLENeedsInterrupt(&BDLE)) 398 { 399 /** @todo Implement / use a (dynamic) table once this gets more complicated. */ 400 #ifdef VBOX_WITH_INTEL_HDA 401 /* Intel ICH / PCH: 1 frame. */ 402 if (BDLE.Desc.u32BufSize == (uint32_t)(1 * pStreamR3->State.Mapping.cbFrameSize)) 403 { 404 cfPosAdjust = 1; 405 } 406 /* Intel Baytrail / Braswell: 32 frames. */ 407 else if (BDLE.Desc.u32BufSize == (uint32_t)(32 * pStreamR3->State.Mapping.cbFrameSize)) 408 { 409 cfPosAdjust = 32; 410 } 411 #endif 412 } 413 else /* Go with the set default. */ 414 cfPosAdjust = pThis->cPosAdjustFrames; 415 416 if (cfPosAdjust) 417 { 418 /* Also adjust the number of fragments, as the position adjustment buffer 419 * does not count as an own fragment as such. 420 * 421 * This e.g. can happen on (newer) Ubuntu guests which use 422 * 4 (IOC) + 4408 (IOC) + 4408 (IOC) + 4408 (IOC) + 4404 (= 17632) bytes, 423 * where the first buffer (4) is used as position adjustment. 424 * 425 * Only skip a fragment if the whole buffer fragment is used for 426 * position adjustment. 427 */ 428 if ((cfPosAdjust * pStreamR3->State.Mapping.cbFrameSize) == BDLE.Desc.u32BufSize) 429 cTransferFragments--; 430 431 /* Initialize position adjustment counter. */ 432 pStreamShared->State.cfPosAdjustDefault = cfPosAdjust; 433 pStreamShared->State.cfPosAdjustLeft = pStreamShared->State.cfPosAdjustDefault; 434 435 LogRel2(("HDA: Position adjustment for stream #%RU8 active (%RU32 frames)\n", 436 uSD, pStreamShared->State.cfPosAdjustDefault)); 437 } 438 } 439 440 Log3Func(("[SD%RU8] cfPosAdjust=%RU32, cFragments=%RU8\n", uSD, cfPosAdjust, cTransferFragments)); 441 442 /* 443 * Set up data transfer stuff. 444 */ 445 446 /* Prevent division by zero. */ 447 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz, 448 ("Timer Hz rate for stream #%RU8 is invalid\n", uSD), 449 pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT); 450 /* 451 * Determine the transfer Hz the guest OS expects data transfer at. 452 * 453 * Guests also expect a very extact DMA timing for reading / writing audio data, so we run on a constant 454 * (virtual) rate which we expose to the guest. 455 * 456 * Data rate examples: 457 * * Windows 10 @ 44,1kHz / 16-bit stereo 458 * * Default mode: 448 audio frames -> ~10.15ms) = 1792 byte every ~10ms. 459 * * Fast mode: 128 audio frames -> ~ 2.90ms) = 512 byte every ~3ms. 460 */ 461 462 /* The transfer Hz depend on the heuristics above, that is, 463 how often the guest expects to see a new data transfer. */ 464 unsigned uTransferHz; 465 466 if (pThis->fTransferHeuristicsEnabled) /* Are data transfer heuristics enabled? */ 467 { 468 469 /* Use the whole CBL as a starting point. 470 * This basically ASSUMES that we have one consequtive buffer with only one interrupt at the end. */ 471 uint32_t cbTransferHeuristicsMin = pStreamShared->u32CBL; 472 473 /* Don't take frames (as bytes) into account which are part of the position adjustment. */ 474 uint32_t cbTransferHeuristicsPosAdjust = pStreamShared->State.cfPosAdjustDefault * pStreamR3->State.Mapping.cbFrameSize; 475 476 HDABDLEDESC bd; 477 uint32_t cbTransferHeuristicsCur = 0; 478 for (uint8_t i = 0; i < cTransferFragments; i++) 479 { 480 PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd)); 481 482 /* Position adjustment (still) needed / active? */ 483 if (cbTransferHeuristicsPosAdjust) 484 { 485 const uint32_t cbTransferHeuristicsPosAdjustMin = RT_MIN(cbTransferHeuristicsPosAdjust, bd.u32BufSize); 486 487 bd.u32BufSize -= cbTransferHeuristicsPosAdjustMin; 488 cbTransferHeuristicsPosAdjust -= cbTransferHeuristicsPosAdjustMin; 489 } 490 491 /* Anything left to process for the current BDLE after doing the position adjustment? */ 492 if (bd.u32BufSize == 0) 493 continue; 494 495 /* Is an interrupt expected for the current BDLE? */ 496 if (bd.fFlags & HDA_BDLE_F_IOC) 497 { 498 cbTransferHeuristicsCur += bd.u32BufSize; 499 cbTransferHeuristicsMin = RT_MIN(cbTransferHeuristicsCur, cbTransferHeuristicsMin); 500 cbTransferHeuristicsCur = 0; 501 } 502 else /* No interrupt expected -> add it to the former BDLE size. */ 503 cbTransferHeuristicsCur += bd.u32BufSize; 504 } 505 506 /* !!! HACK ALERT BEGIN !!! */ 507 508 /* Windows 10's audio driver expects a transfer all ~10.1ms (~1764 bytes), although 509 * it sets up 1792 bytes per BDLE. 510 * 511 * I currently don't have any clue why it does this that way, so try to simply detect this 512 * and alter the value so that we get a somewhat proper audio output. */ 513 if (cbTransferHeuristicsMin == 1792) 514 { 515 LogRel2(("HDA: Guest seems to be Windows 10 -- setting a fixed transfer minimum size\n")); 516 cbTransferHeuristicsMin = 1764; 517 } 518 519 /* !!! HACK ALERT END !!! */ 520 521 uint32_t msTransferHeuristicsMin = DrvAudioHlpBytesToMilli(cbTransferHeuristicsMin, &pCfg->Props); 522 523 /* Prevent division by zero. */ 524 ASSERT_GUEST_LOGREL_MSG_STMT(msTransferHeuristicsMin, 525 ("Transfer heuristics for stream #%RU8 buggy\n", uSD), 526 msTransferHeuristicsMin = 10 /* ms, equals 100 Hz */); 527 528 uTransferHz = RT_MS_1SEC / msTransferHeuristicsMin; 529 530 LogRel2(("HDA: Stream #%RU8 needs a data transfer at least every %RU64ms (%RU32 bytes) -- transfers run at %u Hz\n", 531 uSD, msTransferHeuristicsMin, cbTransferHeuristicsMin, uTransferHz)); 532 } 533 else 534 { 535 /* Use I/O timing rate instead. */ 536 uTransferHz = pStreamShared->State.uTimerIoHz; 537 } 538 539 if (uTransferHz > 400) /* Anything above 400 Hz looks fishy -- tell the user. */ 540 LogRel(("HDA: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), please re-run with audio debug mode and report a bug\n", 541 uSD, uTransferHz)); 542 543 pStreamShared->State.cbTransferSize = 544 (pStreamShared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize) / uTransferHz; 545 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize, 546 ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER); 413 547 if (RT_SUCCESS(rc)) 414 548 { 415 /* Make sure that the chosen Hz rate dividable by the stream's rate. */416 if (pStreamShared->State.Cfg.Props.uHz % pStreamShared->State.uTimerHz != 0)417 LogRel(("HDA: Stream timer Hz rate (%RU32) does not fit to stream #%RU8 timing (%RU32)\n",418 pStreamShared->State.uTimerHz, uSD, pStreamShared->State.Cfg.Props.uHz));419 420 /* Figure out how many transfer fragments we're going to use for this stream. */421 /** @todo Use a more dynamic fragment size? */422 uint8_t cFragments = pStreamShared->u16LVI + 1;423 if (cFragments <= 1)424 cFragments = 2; /* At least two fragments (BDLEs) must be present. */425 426 549 /* 427 * Handle the stream's position adjustment. 550 * Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 551 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. 552 * 553 * As we don't do chunked transfers the moment, the chunk size equals the overall transfer size. 428 554 */ 429 uint32_t cfPosAdjust = 0; 430 431 LogFunc(("[SD%RU8] fPosAdjustEnabled=%RTbool, cPosAdjustFrames=%RU16\n", 432 uSD, pThis->fPosAdjustEnabled, pThis->cPosAdjustFrames)); 433 434 if (pThis->fPosAdjustEnabled) /* Is the position adjustment enabled at all? */ 435 { 436 HDABDLE BDLE; 437 RT_ZERO(BDLE); 438 439 int rc2 = hdaR3BDLEFetch(pDevIns, &BDLE, pStreamShared->u64BDLBase, 0 /* Entry */); 440 AssertRC(rc2); 441 442 /* Note: Do *not* check if this BDLE aligns to the stream's frame size. 443 * It can happen that this isn't the case on some guests, e.g. 444 * on Windows with a 5.1 speaker setup. 445 * 446 * The only thing which counts is that the stream's CBL value 447 * properly aligns to the stream's frame size. 448 */ 449 450 /* If no custom set position adjustment is set, apply some 451 * simple heuristics to detect the appropriate position adjustment. */ 452 if ( !pThis->cPosAdjustFrames 453 /* Position adjustmenet buffer *must* have the IOC bit set! */ 454 && hdaR3BDLENeedsInterrupt(&BDLE)) 455 { 456 /** @todo Implement / use a (dynamic) table once this gets more complicated. */ 457 #ifdef VBOX_WITH_INTEL_HDA 458 /* Intel ICH / PCH: 1 frame. */ 459 if (BDLE.Desc.u32BufSize == (uint32_t)(1 * pStreamR3->State.Mapping.cbFrameSize)) 460 { 461 cfPosAdjust = 1; 462 } 463 /* Intel Baytrail / Braswell: 32 frames. */ 464 else if (BDLE.Desc.u32BufSize == (uint32_t)(32 * pStreamR3->State.Mapping.cbFrameSize)) 465 { 466 cfPosAdjust = 32; 467 } 555 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize; 556 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk, 557 ("Transfer chunk for stream #%RU8 is invalid\n", uSD), 558 rc = VERR_INVALID_PARAMETER); 559 if (RT_SUCCESS(rc)) 560 { 561 /* Make sure that the transfer chunk does not exceed the overall transfer size. */ 562 AssertStmt(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize, 563 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize); 564 565 const uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer); 566 567 const double cTicksPerHz = uTimerFreq / pStreamShared->State.uTimerIoHz; 568 double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk; 569 570 if (pStreamShared->State.uTimerIoHz < uTransferHz) 571 cTicksPerByte /= uTransferHz / pStreamShared->State.uTimerIoHz; 572 else 573 cTicksPerByte *= pStreamShared->State.uTimerIoHz / uTransferHz; 574 575 Assert(cTicksPerByte); 576 577 #define HDA_ROUND_NEAREST(a_X) ((a_X) >= 0 ? (uint32_t)((a_X) + 0.5) : (uint32_t)((a_X) - 0.5)) /** @todo r=andy Do we have rounding in IPRT? */ 578 579 /* Calculate the timer ticks per byte for this stream. */ 580 pStreamShared->State.cTicksPerByte = HDA_ROUND_NEAREST(cTicksPerByte); 581 Assert(pStreamShared->State.cTicksPerByte); 582 583 const double cTransferTicks = pStreamShared->State.cbTransferChunk * cTicksPerByte; 584 585 /* Calculate timer ticks per transfer. */ 586 pStreamShared->State.cTransferTicks = HDA_ROUND_NEAREST(cTransferTicks); 587 Assert(pStreamShared->State.cTransferTicks); 588 589 #undef HDA_ROUND_NEAREST 590 591 LogRel2(("HDA: Stream #%RU8 is using %uHz I/O timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, " 592 "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n", 593 uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamShared->State.Cfg.Props.uHz, 594 pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks, 595 pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pCfg->Props), 596 pStreamShared->State.cbTransferSize, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize, &pCfg->Props))); 597 598 /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */ 599 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD)); 600 601 #ifdef LOG_ENABLED 602 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1); 468 603 #endif 469 } 470 else /* Go with the set default. */ 471 cfPosAdjust = pThis->cPosAdjustFrames; 472 473 if (cfPosAdjust) 474 { 475 /* Also adjust the number of fragments, as the position adjustment buffer 476 * does not count as an own fragment as such. 477 * 478 * This e.g. can happen on (newer) Ubuntu guests which use 479 * 4 (IOC) + 4408 (IOC) + 4408 (IOC) + 4408 (IOC) + 4404 (= 17632) bytes, 480 * where the first buffer (4) is used as position adjustment. 481 * 482 * Only skip a fragment if the whole buffer fragment is used for 483 * position adjustment. 484 */ 485 if ( (cfPosAdjust * pStreamR3->State.Mapping.cbFrameSize) == BDLE.Desc.u32BufSize 486 && cFragments) 487 { 488 cFragments--; 489 } 490 491 /* Initialize position adjustment counter. */ 492 pStreamShared->State.cfPosAdjustDefault = cfPosAdjust; 493 pStreamShared->State.cfPosAdjustLeft = pStreamShared->State.cfPosAdjustDefault; 494 495 LogRel2(("HDA: Position adjustment for stream #%RU8 active (%RU32 frames)\n", 496 uSD, pStreamShared->State.cfPosAdjustDefault)); 497 } 498 } 499 500 LogFunc(("[SD%RU8] cfPosAdjust=%RU32, cFragments=%RU8\n", uSD, cfPosAdjust, cFragments)); 604 } 605 } 606 607 /* 608 * Set up internal ring buffer. 609 */ 610 if (RT_SUCCESS(rc)) 611 { 612 /* (Re-)Allocate the stream's internal DMA buffer, 613 * based on the timing *and* PCM properties we just got above. */ 614 if (pStreamR3->State.pCircBuf) 615 { 616 RTCircBufDestroy(pStreamR3->State.pCircBuf); 617 pStreamR3->State.pCircBuf = NULL; 618 } 501 619 502 620 /* 503 * Set up data transfer stuff. 621 * The default size of our internal ring buffer depends on the transfer timing 622 * we have to reach in order to make the guest driver happy *and* on the I/O timing. 623 * 624 * We always use triple the minimum timing of both timings for safety (triple buffering), 625 * otherwise we risk running into buffer overflows. 504 626 */ 505 506 /* Prevent division by zero. */ 507 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerHz, 508 ("Timer Hz rate for stream #%RU8 is invalid\n", uSD), 509 pStreamShared->State.uTimerHz = HDA_TIMER_HZ_DEFAULT); 510 /* 511 * Calculate the fragment size the guest OS expects interrupt delivery at. 512 * 513 * Guests also expect a very extact DMA timing for reading / writing audio data, so we run on a constant 514 * (virtual) rate which we expose to the guest. 515 * 516 * Data rate examples: 517 * * Windows 10 @ 44,1kHz / 16-bit stereo 518 * * Default mode: 448 audio frames (~10.15ms) = 1792 byte / ~10ms. 519 * * Fast mode: 128 audio frames (~ 2.90ms) = 512 byte / ~3ms. 520 */ 521 pStreamShared->State.cbTransferSize 522 = (pStreamShared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize) / pStreamShared->State.uTimerHz; 523 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize, 524 ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER); 627 const unsigned uTransferHzMin = RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz); 628 629 uint32_t cbCircBuf; 630 const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes((RT_MS_1SEC / uTransferHzMin) * 3, &pCfg->Props); 631 632 LogRel2(("HDA: Stream #%RU8 default ring buffer size is %RU64ms (%RU32 bytes)\n", 633 uSD, DrvAudioHlpBytesToMilli(cbCircBufDefault, &pCfg->Props), cbCircBufDefault)); 634 635 uint32_t cbCircBufGlobal = DrvAudioHlpMilliToBytes( hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN 636 ? pThis->cbCircBufInMs : pThis->cbCircBufOutMs, &pCfg->Props); 637 if (cbCircBufGlobal) /* Anything set via CFGM? */ 638 { 639 640 ASSERT_GUEST_LOGREL_MSG_STMT(DrvAudioHlpBytesIsAligned(cbCircBufGlobal, &pCfg->Props), 641 ("Ring buffer size for stream #%RU8 is misaligned (%zu), setting to default\n", uSD, cbCircBufGlobal), 642 cbCircBufGlobal = cbCircBufDefault); 643 644 LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU64ms (%RU32 bytes)\n", 645 uSD, DrvAudioHlpBytesToMilli(cbCircBufGlobal, &pCfg->Props), cbCircBufGlobal)); 646 647 cbCircBuf = cbCircBufGlobal; 648 } 649 else 650 cbCircBuf = cbCircBufDefault; 651 652 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf, 653 ("Ring buffer size for stream #%RU8 is invalid\n", uSD), 654 rc = VERR_INVALID_PARAMETER); 525 655 if (RT_SUCCESS(rc)) 526 { 527 /* 528 * Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 529 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. 530 * 531 * As we don't do chunked transfers the moment, the chunk size equals the overall transfer size. 532 */ 533 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize; 534 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk, 535 ("Transfer chunk for stream #%RU8 is invalid\n", uSD), 536 rc = VERR_INVALID_PARAMETER); 537 if (RT_SUCCESS(rc)) 538 { 539 /* Make sure that the transfer chunk does not exceed the overall transfer size. */ 540 AssertStmt(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize, 541 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize); 542 543 const uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer); 544 545 const double cTicksPerHz = uTimerFreq / pStreamShared->State.uTimerHz; 546 const double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk; 547 548 #define HDA_ROUND_NEAREST(a_X) ((a_X) >= 0 ? (uint32_t)((a_X) + 0.5) : (uint32_t)((a_X) - 0.5)) /** @todo r=andy Do we have rounding in IPRT? */ 549 550 /* Calculate the timer ticks per byte for this stream. */ 551 pStreamShared->State.cTicksPerByte = HDA_ROUND_NEAREST(cTicksPerByte); 552 Assert(pStreamShared->State.cTicksPerByte); 553 554 const double cTransferTicks = pStreamShared->State.cbTransferChunk * cTicksPerByte; 555 556 /* Calculate timer ticks per transfer. */ 557 pStreamShared->State.cTransferTicks = HDA_ROUND_NEAREST(cTransferTicks); 558 Assert(pStreamShared->State.cTransferTicks); 559 560 #undef HDA_ROUND_NEAREST 561 562 LogRel2(("HDA: Stream #%RU8 is using %uHz device timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, " 563 "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n", 564 uSD, pStreamShared->State.uTimerHz, (uint64_t)cTicksPerHz, pStreamShared->State.Cfg.Props.uHz, 565 pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks, 566 pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pCfg->Props), 567 pStreamShared->State.cbTransferSize, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize, &pCfg->Props))); 568 569 /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */ 570 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD)); 571 572 #ifdef LOG_ENABLED 573 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1); 574 #endif 575 } 576 } 656 rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBuf); 577 657 } 578 658 … … 641 721 pStreamShared->State.tsTransferNext = 0; 642 722 643 /* Initialize other timestamps. */ 644 pStreamShared->State.tsLastUpdateNs = 0; 723 /* Initialize timestamps. */ 724 pStreamShared->State.tsLastTransferNs = 0; 725 pStreamShared->State.tsLastReadNs = 0; 645 726 646 727 RT_ZERO(pStreamShared->State.BDLE); … … 1046 1127 } 1047 1128 1129 /* Update real-time timestamp. */ 1130 const uint64_t tsNowNs = RTTimeNanoTS(); 1131 #ifdef LOG_ENABLED 1132 const uint64_t tsDeltaMs = (tsNowNs - pStreamShared->State.tsLastTransferNs) / RT_NS_1MS; 1133 Log3Func(("[SD%RU8] tsDeltaNs=%RU64ms\n", uSD, tsDeltaMs)); 1134 #endif 1135 pStreamShared->State.tsLastTransferNs = tsNowNs; 1136 1048 1137 const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1049 1138 1050 1139 if (!pStreamShared->State.tsTransferLast) 1051 1140 pStreamShared->State.tsTransferLast = tsNow; 1052 1053 #ifdef DEBUG1054 const int64_t iTimerDelta = tsNow - pStreamShared->State.tsTransferLast;1055 Log3Func(("[SD%RU8] Time now=%RU64, last=%RU64 -> %RI64 ticks delta\n",1056 uSD, tsNow, pStreamShared->State.tsTransferLast, iTimerDelta));1057 #endif1058 1141 1059 1142 pStreamShared->State.tsTransferLast = tsNow; … … 1097 1180 uint32_t cbProcessed = 0; 1098 1181 uint32_t cbLeft = cbToProcess; 1182 1183 /* Whether an interrupt has been sent (asserted) for this transfer period already or not. 1184 * 1185 * Note: Windows 10 relies on this, e.g. sending more than one interrupt per transfer period 1186 * confuses the Windows' audio driver and will screw up the audio data. So only send 1187 * one interrupt per transfer period. 1188 */ 1189 bool fInterruptSent = false; 1099 1190 1100 1191 while (cbLeft) … … 1370 1461 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE) 1371 1462 { 1372 pStreamShared->State.cTransferPendingInterrupts++;1373 1374 AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32,1375 ("Too many pending interrupts (%RU8) for stream #%RU8\n",1376 pStreamShared->State.cTransferPendingInterrupts, uSD));1377 1378 1463 /* Assert the interrupt before actually fetching the next BDLE below. */ 1379 if ( pStreamShared->State.cTransferPendingInterrupts)1464 if (!fInterruptSent) 1380 1465 { 1466 pStreamShared->State.cTransferPendingInterrupts++; 1467 1468 AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32, 1469 ("Too many pending interrupts (%RU8) for stream #%RU8\n", 1470 pStreamShared->State.cTransferPendingInterrupts, uSD)); 1471 1381 1472 Log3Func(("[SD%RU8] Scheduling interrupt (now %RU8 total)\n", uSD, pStreamShared->State.cTransferPendingInterrupts)); 1382 1473 … … 1397 1488 * ending / beginning a period. */ 1398 1489 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 1490 1491 fInterruptSent = true; 1399 1492 } 1400 1493 } … … 1463 1556 /* No, set relative timer ticks for the next transfer to happen. 1464 1557 * This must happen at a constant rate. */ 1465 tsTransferNext = pStreamShared->State.cTransferTicks;1558 tsTransferNext = tsNow + pStreamShared->State.cTransferTicks; 1466 1559 } 1467 1560 … … 1469 1562 if (tsTransferNext) /* Can be 0 if no next transfer is needed. */ 1470 1563 { 1471 Log3Func(("[SD%RU8] Scheduling timer @ %RU64\n", uSD, tsNow + tsTransferNext)); 1564 Log3Func(("[SD%RU8] Scheduling timer @ %RU64\n", uSD, tsTransferNext)); 1565 1566 /* Make sure to assign next transfer timestamp before setting the timer. */ 1567 pStreamShared->State.tsTransferNext = tsTransferNext; 1472 1568 1473 1569 Assert(!fInTimer || tsNow == PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer)); 1474 1570 hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext, 1475 1571 true /* fForce - skip tsTransferNext check */, fInTimer ? tsNow : 0); 1476 1477 pStreamShared->State.tsTransferNext = tsTransferNext;1478 1572 } 1479 1573 … … 1532 1626 return; 1533 1627 1628 const uint64_t tsNowNs = RTTimeNanoTS(); 1629 1534 1630 int rc2; 1535 1631 … … 1551 1647 /* When hitting an overflow, drop all remaining data to make space for current data. 1552 1648 * This is needed in order to keep the device emulation running at a constant rate, 1553 * at the cost of losing olddata. */1649 * at the cost of losing valid (but too much) data. */ 1554 1650 RTCircBufReset(pStreamR3->State.pCircBuf); 1555 1651 cbStreamFree = hdaR3StreamGetFree(pStreamR3); … … 1560 1656 AssertRC(rc2); 1561 1657 1562 const uint64_t tsNowNs = RTTimeNanoTS(); 1563 1564 /* Never updated yet? Set initial timestamp. */ 1565 if (pStreamShared->State.tsLastUpdateNs == 0) 1566 pStreamShared->State.tsLastUpdateNs = tsNowNs; 1658 /* Never read yet? Set initial timestamp. */ 1659 if (pStreamShared->State.tsLastReadNs == 0) 1660 pStreamShared->State.tsLastReadNs = tsNowNs; 1567 1661 1568 1662 /* Only read from the HDA stream at the given scheduling rate. */ 1569 if (tsNowNs - pStreamShared->State.tsLastUpdateNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1570 { 1663 Assert(tsNowNs >= pStreamShared->State.tsLastReadNs); 1664 const uint64_t tsDeltaMs = (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS; 1665 if (tsDeltaMs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint) 1571 1666 fDoRead = true; 1572 pStreamShared->State.tsLastUpdateNs = tsNowNs; 1573 }1574 } 1575 Log3Func(("[SD%RU8] fInTimer=%RTbool, tsLastUpdateNs=%RU64, fDoRead=%RTbool\n", 1576 pStreamShared->u8SD, fInTimer, pStreamShared->State.tsLastUpdateNs, fDoRead));1577 1667 1668 Log3Func(("tsDeltaMs=%RU64, fDoRead=%RTbool\n", tsDeltaMs, fDoRead)); 1669 } 1670 1671 if (fDoRead) 1672 { 1578 1673 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1579 if (fDoRead) 1580 { 1674 /* Notify the async I/O worker thread that there's work to do. */ 1581 1675 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 1582 1676 AssertRC(rc2); 1583 }1584 1677 # endif 1678 /* Update last read timestamp so that we know when to run next. */ 1679 pStreamShared->State.tsLastReadNs = tsNowNs; 1680 } 1585 1681 1586 1682 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO … … 1596 1692 cbToReadFromStream = DrvAudioHlpBytesAlign(cbToReadFromStream, &pStreamShared->State.Cfg.Props); 1597 1693 1598 Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStreamShared->u8SD, cbSinkWritable, cbStreamReadable)); 1694 #ifdef LOG_ENABLED 1695 Assert(tsNowNs >= pStreamShared->State.tsLastReadNs); 1696 const uint64_t deltaLastReadMs = (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS; 1697 Log3Func(("[SD%RU8] deltaLastReadMs=%RU64\n", 1698 pStreamShared->u8SD, deltaLastReadMs)); 1699 #endif 1700 Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32 -> cbToReadFromStream=%RU32\n", 1701 pStreamShared->u8SD, cbSinkWritable, cbStreamReadable, cbToReadFromStream)); 1599 1702 1600 1703 if (cbToReadFromStream) … … 1666 1769 { 1667 1770 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1668 const uint64_t tsNowNs = RTTimeNanoTS(); 1669 if (tsNowNs - pStreamShared->State.tsLastUpdateNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1771 if (tsNowNs - pStreamShared->State.tsLastReadNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1670 1772 { 1671 1773 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 1672 1774 AssertRC(rc2); 1673 1775 1674 pStreamShared->State.tsLast UpdateNs = tsNowNs;1776 pStreamShared->State.tsLastReadNs = tsNowNs; 1675 1777 } 1676 1778 # endif -
trunk/src/VBox/Devices/Audio/HDAStream.h
r87569 r87758 126 126 /** Current BDLE (Buffer Descriptor List Entry). */ 127 127 HDABDLE BDLE; 128 /** Timestamp of the last DMA data transfer. */128 /** Timestamp (absolute, in timer ticks) of the last DMA data transfer. */ 129 129 uint64_t tsTransferLast; 130 /** Timestamp of the next DMA data transfer.130 /** Timestamp (absolute, in timer ticks) of the next DMA data transfer. 131 131 * Next for determining the next scheduling window. 132 132 * Can be 0 if no next transfer is scheduled. */ … … 140 140 uint8_t cTransferPendingInterrupts; 141 141 uint8_t abPadding2[7]; 142 /** The stream's timer Hz rate. 143 * This value can can be different from the device's default Hz rate, 144 * depending on the rate the stream expects (e.g. for 5.1 speaker setups). 145 * Set in hdaR3StreamInit(). */ 146 uint16_t uTimerHz; 142 /** The stream's I/O timer Hz rate. */ 143 uint16_t uTimerIoHz; 147 144 /** Number of audio data frames for the position adjustment. 148 145 * 0 if no position adjustment is needed. */ … … 163 160 * Should match SDFMT. */ 164 161 PDMAUDIOSTREAMCFG Cfg; 165 /** Timestamp (in ns) of last stream update. */ 166 uint64_t tsLastUpdateNs; 162 /** Timestamp (real time, in ns) of last DMA transfer. */ 163 uint64_t tsLastTransferNs; 164 /** Timestamp (real time, in ns) of last stream read (to backends). 165 * When running in async I/O mode, this differs from \a tsLastTransferNs, 166 * because reading / processing will be done in a separate stream. */ 167 uint64_t tsLastReadNs; 167 168 } HDASTREAMSTATE; 168 169 AssertCompileSizeAlignment(HDASTREAMSTATE, 8); -
trunk/src/VBox/Devices/Audio/HDAStreamPeriod.cpp
r82968 r87758 109 109 cTotalPeriods = 2; /* At least two periods *must* be present (LVI >= 1). */ 110 110 111 uint32_t cFramesToTransfer = (u32CBL / 4 /** @todo Define frame size? */) / cTotalPeriods; 112 113 pPeriod->u8SD = u8SD; 114 pPeriod->u64StartWalClk = 0; 115 pPeriod->u32Hz = pStreamCfg->Props.uHz; 116 pPeriod->u64DurationWalClk = hdaR3StreamPeriodFramesToWalClk(pPeriod, cFramesToTransfer); 117 pPeriod->u64ElapsedWalClk = 0; 118 pPeriod->i64DelayWalClk = 0; 111 uint32_t cFramesToTransfer = 112 (u32CBL / (pStreamCfg->Props.cbSample * pStreamCfg->Props.cChannels /* Frame size */)) / cTotalPeriods; 113 114 pPeriod->u8SD = u8SD; 115 pPeriod->u64StartWalClk = 0; 116 pPeriod->u32Hz = pStreamCfg->Props.uHz; 117 pPeriod->u64DurationWalClk = hdaR3StreamPeriodFramesToWalClk(pPeriod, cFramesToTransfer); 118 pPeriod->u64ElapsedWalClk = 0; 119 pPeriod->i64DelayWalClk = 0; 119 120 pPeriod->cFramesToTransfer = cFramesToTransfer; 120 121 pPeriod->cFramesTransferred = 0; 121 pPeriod->cIntPending = 0;122 pPeriod->cIntPending = 0; 122 123 123 124 Log3Func(("[SD%RU8] %RU64 long, Hz=%RU32, CBL=%RU32, LVI=%RU16 -> %u periods, %RU32 frames each\n",
Note:
See TracChangeset
for help on using the changeset viewer.