Changeset 88112 in vbox for trunk/src/VBox
- Timestamp:
- Mar 12, 2021 8:41:05 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143255
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r88094 r88112 5200 5200 "The stream frequency.", "Stream%u/Cfg/Hz", idxStream); 5201 5201 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cChannels, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5202 "The number of channels.", "Stream%u/Cfg/Channels", idxStream); 5202 "The number of channels.", "Stream%u/Cfg/Channels-Host", idxStream); 5203 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.Mapping.GuestProps.cChannels, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5204 "The number of channels.", "Stream%u/Cfg/Channels-Guest", idxStream); 5203 5205 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbSample, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5204 5206 "The size of a sample (per channel).", "Stream%u/Cfg/cbSample", idxStream); -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r88097 r88112 265 265 } 266 266 267 PDMAUDIOPCMPROPS Props;268 int rc = hdaR3SDFMTToPCMProps(u16FMT, & Props);267 PDMAUDIOPCMPROPS HostProps; 268 int rc = hdaR3SDFMTToPCMProps(u16FMT, &HostProps); 269 269 if (RT_FAILURE(rc)) 270 270 { … … 272 272 return rc; 273 273 } 274 275 /* Reset (any former) stream map. */276 hdaR3StreamMapReset(&pStreamR3->State.Mapping);277 274 278 275 /* … … 284 281 * number of channels in a single audio stream. 285 282 */ 286 rc = hdaR3StreamMapInit(&pStreamR3->State.Mapping, &Props); 283 /** @todo r=bird: this is not done at the wrong time. We don't have the host 284 * output side set up yet, so we cannot really do proper mapping setup. 285 * However, we really need this further down when we configure the internal DMA 286 * buffer size. For now we just assume it's all stereo on the host side. 287 * This is not compatible with microphone support. */ 288 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN 289 # error "Implement me!" 290 # endif 291 rc = hdaR3StreamMapInit(&pStreamR3->State.Mapping, 2 /*cHostChannels*/, &HostProps); 287 292 AssertRCReturn(rc, rc); 288 293 289 ASSERT_GUEST_LOGREL_MSG_RETURN( pStreamR3->State.Mapping.cb FrameSize > 0290 && u32CBL % pStreamR3->State.Mapping.cb FrameSize == 0,294 ASSERT_GUEST_LOGREL_MSG_RETURN( pStreamR3->State.Mapping.cbGuestFrame > 0 295 && u32CBL % pStreamR3->State.Mapping.cbGuestFrame == 0, 291 296 ("CBL for stream #%RU8 does not align to frame size (u32CBL=%u cbFrameSize=%u)\n", 292 uSD, u32CBL, pStreamR3->State.Mapping.cb FrameSize),297 uSD, u32CBL, pStreamR3->State.Mapping.cbGuestFrame), 293 298 VERR_INVALID_PARAMETER); 294 295 #ifndef VBOX_WITH_AUDIO_HDA_51_SURROUND296 if (Props.cChannels > 2)297 {298 /*299 * When not running with surround support enabled, override the audio channel count300 * with stereo (2) channels so that we at least can properly work with those.301 *302 * Note: This also involves dealing with surround setups the guest might has set up for us.303 */304 LogRelMax(32, ("HDA: Warning: More than stereo (2) channels are not supported (%RU8 requested), falling back to stereo channels for stream #%RU8\n",305 Props.cChannels, uSD));306 Props.cChannels = 2;307 Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(Props.cbSample, Props.cChannels);308 }309 #endif310 299 311 300 /* Make sure the guest behaves regarding the stream's FIFO. */ … … 325 314 326 315 PPDMAUDIOSTREAMCFG pCfg = &pStreamShared->State.Cfg; 327 pCfg->Props = Props;316 pCfg->Props = HostProps; 328 317 329 318 /* Set the stream's direction. */ … … 344 333 345 334 case PDMAUDIODIR_OUT: 346 /* Destination(s) will be set in hda AddStreamOut(),335 /* Destination(s) will be set in hdaR3AddStreamOut(), 347 336 * based on the channels / stream layout. */ 348 337 break; … … 355 344 LogRel2(("HDA: Stream #%RU8 DMA @ 0x%x (%RU32 bytes = %RU64ms total)\n", 356 345 uSD, pStreamShared->u64BDLBase, pStreamShared->u32CBL, 357 PDMAudioPropsBytesToMilli(&pStreamR3->State.Mapping. PCMProps, pStreamShared->u32CBL)));346 PDMAudioPropsBytesToMilli(&pStreamR3->State.Mapping.GuestProps, pStreamShared->u32CBL))); 358 347 359 348 /* Figure out how many transfer fragments we're going to use for this stream. */ … … 396 385 #ifdef VBOX_WITH_INTEL_HDA 397 386 /* Intel ICH / PCH: 1 frame. */ 398 if (BDLE.Desc.u32BufSize == (uint32_t)(1 * pStreamR3->State.Mapping.cb FrameSize))387 if (BDLE.Desc.u32BufSize == (uint32_t)(1 * pStreamR3->State.Mapping.cbGuestFrame)) 399 388 { 400 389 cfPosAdjust = 1; 401 390 } 402 391 /* Intel Baytrail / Braswell: 32 frames. */ 403 else if (BDLE.Desc.u32BufSize == (uint32_t)(32 * pStreamR3->State.Mapping.cb FrameSize))392 else if (BDLE.Desc.u32BufSize == (uint32_t)(32 * pStreamR3->State.Mapping.cbGuestFrame)) 404 393 { 405 394 cfPosAdjust = 32; … … 422 411 * position adjustment. 423 412 */ 424 if ((cfPosAdjust * pStreamR3->State.Mapping.cb FrameSize) == BDLE.Desc.u32BufSize)413 if ((cfPosAdjust * pStreamR3->State.Mapping.cbGuestFrame) == BDLE.Desc.u32BufSize) 425 414 cTransferFragments--; 426 415 … … 457 446 458 447 /* Audio data per second the stream needs. */ 459 const uint32_t cbDataPerSec = PDMAudioPropsMilliToBytes(&pStreamR3->State.Mapping. PCMProps, RT_MS_1SEC);448 const uint32_t cbDataPerSec = PDMAudioPropsMilliToBytes(&pStreamR3->State.Mapping.GuestProps, RT_MS_1SEC); 460 449 461 450 /* This is used to indicate whether we're done or should the uTimerIoHz as fallback. */ … … 469 458 unsigned uTransferHz = pStreamShared->State.uTimerIoHz; 470 459 471 LogRel2(("HDA: Stream #%RU8 needs %RU32 bytes/s audio data \n", uSD, cbDataPerSec));460 LogRel2(("HDA: Stream #%RU8 needs %RU32 bytes/s audio data (from the guest).\n", uSD, cbDataPerSec)); 472 461 473 462 if (pThis->fTransferHeuristicsEnabled) /* Are data transfer heuristics enabled? */ 474 463 { 475 464 /* Don't take frames (as bytes) into account which are part of the position adjustment. */ 476 uint32_t cbTransferHeuristicsPosAdjust = pStreamShared->State.cfPosAdjustDefault * pStreamR3->State.Mapping.cb FrameSize;465 uint32_t cbTransferHeuristicsPosAdjust = pStreamShared->State.cfPosAdjustDefault * pStreamR3->State.Mapping.cbGuestFrame; 477 466 uint32_t cbTransferHeuristics = 0; 478 467 uint32_t cbTransferHeuristicsCur = 0; … … 533 522 if (cbTransferHeuristics >= 8) 534 523 { 535 ASSERT_GUEST_LOGREL_MSG(PDMAudioPropsIsSizeAligned(&pStreamR3->State.Mapping. PCMProps, cbTransferHeuristics),524 ASSERT_GUEST_LOGREL_MSG(PDMAudioPropsIsSizeAligned(&pStreamR3->State.Mapping.GuestProps, cbTransferHeuristics), 536 525 ("We arrived at a misaligned transfer size for stream #%RU8: %#x (%u)\n", 537 526 uSD, cbTransferHeuristics, cbTransferHeuristics)); 538 527 539 528 uint64_t const cTimerTicksPerSec = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer); 540 uint64_t const cbTransferPerSec = RT_MAX(pStreamR3->State.Mapping.PCMProps.uHz * pStreamR3->State.Mapping.cbFrameSize, 529 530 /* Convert the heuristics value to host side bytes and that's what we're calculating. */ 531 cbTransferHeuristics = PDMAudioPropsBytesToFrames(&pStreamR3->State.Mapping.GuestProps, cbTransferHeuristics); 532 cbTransferHeuristics = PDMAudioPropsFramesToBytes(&pCfg->Props, cbTransferHeuristics); 533 534 uint64_t const cbTransferPerSec = RT_MAX(PDMAudioPropsFramesToBytes(&pCfg->Props, pCfg->Props.uHz), 541 535 4096 /* zero div prevention: min is 6kHz, picked 4k in case I'm mistaken */); 542 536 … … 545 539 halve the buffer till we get there. */ 546 540 while (cbTransferHeuristics > 1024 && cbTransferHeuristics > cbTransferPerSec / 4) 547 cbTransferHeuristics = PDMAudioPropsFloorBytesToFrame(&p StreamR3->State.Mapping.PCMProps, cbTransferHeuristics / 2);541 cbTransferHeuristics = PDMAudioPropsFloorBytesToFrame(&pCfg->Props, cbTransferHeuristics / 2); 548 542 549 543 /* Set the transfer size per timer callout. (No chunking, so same.) */ 550 544 pStreamShared->State.cbTransferSize = cbTransferHeuristics; 551 545 pStreamShared->State.cbTransferChunk = cbTransferHeuristics; 552 ASSERT_GUEST_LOGREL_MSG(PDMAudioPropsIsSizeAligned(&p StreamR3->State.Mapping.PCMProps, cbTransferHeuristics),546 ASSERT_GUEST_LOGREL_MSG(PDMAudioPropsIsSizeAligned(&pCfg->Props, cbTransferHeuristics), 553 547 ("We arrived at a misaligned transfer size for stream #%RU8: %#x (%u)\n", 554 548 uSD, cbTransferHeuristics, cbTransferHeuristics)); … … 594 588 uTransferHz = HDA_TIMER_HZ_DEFAULT); 595 589 596 pStreamShared->State.cbTransferSize = (pStreamR3->State.Mapping. PCMProps.uHz * pStreamR3->State.Mapping.cbFrameSize)590 pStreamShared->State.cbTransferSize = (pStreamR3->State.Mapping.GuestProps.uHz * pStreamR3->State.Mapping.cbGuestFrame) 597 591 / uTransferHz; 598 592 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize, … … 641 635 642 636 LogRel2(("HDA: Stream #%RU8 is using %uHz I/O timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n", 643 uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamR3->State.Mapping. PCMProps.uHz,637 uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamR3->State.Mapping.GuestProps.uHz, 644 638 pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks, 645 pStreamShared->State.cbTransferChunk, PDMAudioPropsBytesToMilli(&pStreamR3->State.Mapping. PCMProps, pStreamShared->State.cbTransferChunk),646 pStreamShared->State.cbTransferSize, PDMAudioPropsBytesToMilli(&pStreamR3->State.Mapping. PCMProps, pStreamShared->State.cbTransferSize)));639 pStreamShared->State.cbTransferChunk, PDMAudioPropsBytesToMilli(&pStreamR3->State.Mapping.GuestProps, pStreamShared->State.cbTransferChunk), 640 pStreamShared->State.cbTransferSize, PDMAudioPropsBytesToMilli(&pStreamR3->State.Mapping.GuestProps, pStreamShared->State.cbTransferSize))); 647 641 } 648 642 } … … 979 973 * @param pDevIns The device instance. 980 974 * @param pThis The shared HDA device state. 981 * @param uToAdd Position (in bytes) to add to the current read / write position. 982 */ 983 void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd) 984 { 985 if (!uToAdd) /* No need to update anything if 0. */ 986 return; 987 988 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, 989 (HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + uToAdd) % pStreamShared->u32CBL); 975 * @param cbToAdd Position (in bytes) to add to the current read / write position. 976 */ 977 void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t cbToAdd) 978 { 979 if (cbToAdd) /* No need to update anything if 0. */ 980 { 981 uint32_t const uCBL = pStreamShared->u32CBL; 982 if (uCBL) /* paranoia */ 983 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, 984 (HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + cbToAdd) % uCBL); 985 } 990 986 } 991 987 … … 1296 1292 * make sure that we process them first as a whole. */ 1297 1293 if (pStreamShared->State.cfPosAdjustLeft) 1298 cbChunk = RT_MIN(cbChunk, (uint32_t)pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cb FrameSize);1294 cbChunk = RT_MIN(cbChunk, (uint32_t)pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbGuestFrame); 1299 1295 1300 1296 if (!cbChunk) … … 1368 1364 * Only macOS guests need the frame extraction branch below at the moment AFAIK. 1369 1365 */ 1370 if (pStreamR3->State.Mapping.cb FrameSize == HDA_FRAME_SIZE_DEFAULT)1366 if (pStreamR3->State.Mapping.cbGuestFrame == HDA_FRAME_SIZE_DEFAULT) 1371 1367 { 1372 1368 uint32_t cbDMARead = 0; … … 1410 1406 for (unsigned m = 0; m < pStreamR3->State.Mapping.cMappings; m++) 1411 1407 { 1412 const uint32_t cbFrame = pStreamR3->State.Mapping.cb FrameSize;1408 const uint32_t cbFrame = pStreamR3->State.Mapping.cbGuestFrame; 1413 1409 1414 1410 Assert(cbFree >= cbDMA); … … 1546 1542 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1547 1543 pBDLE->Desc.u32BufSize 1548 / pStreamR3->State.Mapping.cb FrameSize),1544 / pStreamR3->State.Mapping.cbGuestFrame), 1549 1545 false /* fForce */); 1550 1546 … … 1619 1615 /* Do the position adjustment accounting. */ 1620 1616 pStreamShared->State.cfPosAdjustLeft -= 1621 RT_MIN(pStreamShared->State.cfPosAdjustLeft, cbDMA / pStreamR3->State.Mapping.cb FrameSize);1617 RT_MIN(pStreamShared->State.cfPosAdjustLeft, cbDMA / pStreamR3->State.Mapping.cbGuestFrame); 1622 1618 1623 1619 if (RT_FAILURE(rc)) … … 1636 1632 if (pStreamShared->State.cfPosAdjustLeft == 0) 1637 1633 { 1638 hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cb FrameSize,1634 hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbGuestFrame, 1639 1635 hdaR3StreamPeriodGetRemainingFrames(pPeriod))); 1640 1636 } … … 1659 1655 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1660 1656 cbProcessed 1661 / pStreamR3->State.Mapping.cb FrameSize),1657 / pStreamR3->State.Mapping.cbGuestFrame), 1662 1658 hdaR3WalClkGetMax(pThis, pThisCC)), 1663 1659 false /* fForce */); … … 1700 1696 * @param pStreamShared HDA stream to update (shared). 1701 1697 * @param pStreamR3 HDA stream to update (ring-3). 1702 * @param cbToProcessMax How much data (in bytes) to process as maximum. 1703 * Caller should already have made sure this is at 1704 * least one 1698 * @param cbToProduce The max amount of data to produce (i.e. put into 1699 * the circular buffer). (Caller should already 1700 * have made sure this is at least the size of one 1701 * DMA timer period, so this function doesn't need 1702 * to do any extra underflow handling.) 1703 * @param tsNowNs The current RTTimeNano() value. 1704 * 1705 1705 * @remarks Caller owns the stream lock. 1706 1706 */ 1707 1707 static int hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, 1708 PHDASTREAMR3 pStreamR3, uint32_t cbToPro cessMax, uint64_t tsNowNs)1708 PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs) 1709 1709 { 1710 1710 PHDASTREAMPERIOD const pPeriod = &pStreamShared->State.Period; 1711 1711 uint8_t const uSD = pStreamShared->u8SD; 1712 LogFlowFunc(("ENTER - #%u cbToPro cessMax=%#x\n", uSD, cbToProcessMax));1712 LogFlowFunc(("ENTER - #%u cbToProduce=%#x\n", uSD, cbToProduce)); 1713 1713 1714 1714 … … 1778 1778 * of buffer available. We will not transfer more than that. 1779 1779 */ 1780 uint8_t cSuppressIocs = 0; 1780 1781 Assert(pStreamShared->State.cbTransferChunk == pStreamShared->State.cbTransferSize); 1781 Assert(cbToProcessMax >= pStreamShared->State.cbTransferSize); 1782 if (cbToProcessMax > pStreamShared->State.cbTransferSize) 1783 cbToProcessMax = pStreamShared->State.cbTransferSize; 1784 uint32_t cbLeft = cbToProcessMax; 1782 if (!pStreamShared->State.cfPosAdjustLeft) 1783 { 1784 Assert(cbToProduce >= pStreamShared->State.cbTransferSize); 1785 if (cbToProduce > pStreamShared->State.cbTransferSize) 1786 cbToProduce = pStreamShared->State.cbTransferSize; 1787 } 1788 else 1789 { 1790 /* We currently process the position adjustment BLDE0 and the whole BLDE1 1791 in one DMA timer callout, ignoring BLDE0.IOC. */ 1792 /** @todo Process the tiny BLDE0 seperatly. */ 1793 uint32_t const cbPosAdjust = PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, 1794 pStreamShared->State.cfPosAdjustLeft); 1795 Assert(cbToProduce >= pStreamShared->State.cbTransferSize + cbPosAdjust); 1796 if (cbToProduce >= pStreamShared->State.cbTransferSize + cbPosAdjust) 1797 { 1798 cbToProduce = pStreamShared->State.cbTransferSize + cbPosAdjust; 1799 pStreamShared->State.cfPosAdjustLeft = 0; 1800 cSuppressIocs = pBDLE->Desc.fFlags & HDA_BDLE_F_IOC ? 1 : 0; 1801 } 1802 else 1803 pStreamShared->State.cfPosAdjustLeft -= PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbToProduce); 1804 } 1805 uint32_t cbLeft = cbToProduce; 1806 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft)); 1785 1807 1786 1808 /* … … 1796 1818 * Unless the buffers are really small, this is stuff that won't happen 1797 1819 * on real hardware. */ 1798 /** @todo Disallow non-heuristics approach! It only complicates the code. */ 1820 /** @todo Disallow non-heuristics approach! It only complicates the code 1821 * and messes with the guest if we cover more than one IOC! */ 1799 1822 bool fInterruptSent = false; 1800 1823 … … 1807 1830 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY; 1808 1831 1809 while (cbLeft) 1810 { 1811 /* Limit the chunk to the stream's FIFO size and what's left to process. */ 1812 uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u8FIFOS); 1813 1814 /* Limit the chunk to the remaining data of the current BDLE. */ 1815 cbChunk = RT_MIN(cbChunk, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff); 1816 1817 /* If there are position adjustment frames left to be processed, 1818 * make sure that we process them first as a whole. */ 1819 if (pStreamShared->State.cfPosAdjustLeft) 1820 cbChunk = RT_MIN(cbChunk, (uint32_t)pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize); 1821 1822 /** @todo wtf is this for? Move on to the next BDLE! */ 1823 if (!cbChunk) 1824 break; 1825 1826 uint32_t cbDMA = 0; 1827 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf; 1828 uint8_t *pabFIFO = pStreamShared->abFIFO; 1829 1832 /* 1833 * 1834 * The DMA copy loop. 1835 * 1836 */ 1837 uint8_t abBounce[4096 + 128]; /* Most guest does at most 4KB BDLE. So, 4KB + space for a partial frame to reduce loops. */ 1838 uint32_t cbBounce = 0; /* in case of incomplete frames between buffer segments */ 1839 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf; 1840 while (cbLeft > 0) 1841 { 1830 1842 STAM_PROFILE_START(&pThis->StatOut, a); 1831 1843 1832 rc = hdaR3DMARead(pDevIns, pThis, pStreamShared, pStreamR3, pabFIFO, cbChunk, &cbDMA /* pcbRead */); 1833 if (RT_SUCCESS(rc)) 1844 /* 1845 * Figure out how much we can read & write in this iteration. 1846 */ 1847 uint32_t cbChunk = pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff; 1848 AssertStmt(cbChunk <= pBDLE->Desc.u32BufSize, cbChunk = 0); 1849 1850 /* Need to diverge if the frame format differs. */ 1851 if ( !pStreamR3->State.Mapping.fMappingNeeded 1852 /** @todo && pStreamShared->State.fFrameAlignedBuffers */) 1834 1853 { 1835 /** @todo wtf? Caller passed us the RTCircBufFree value via cbToProcessMax. */ 1836 const uint32_t cbFree = (uint32_t)RTCircBufFree(pCircBuf); 1854 if (cbChunk <= cbLeft) 1855 { /* very likely */ } 1856 else 1857 cbChunk = cbLeft; 1837 1858 1838 1859 /* 1839 * Most guests don't use different stream frame sizes than 1840 * the default one, so save a bit of CPU time and don't go into 1841 * the frame extraction code below. 1842 * 1843 * Only macOS guests need the frame extraction branch below at the moment AFAIK. 1860 * Read the guest data directly into the internal DMA buffer. 1844 1861 */ 1845 if (pStreamR3->State.Mapping.cbFrameSize == HDA_FRAME_SIZE_DEFAULT) 1862 RTGCPHYS GCPhys = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff; 1863 while (cbChunk > 0) 1846 1864 { 1847 uint32_t cbDMARead = 0; 1848 uint32_t cbDMALeft = RT_MIN(cbDMA, cbFree); 1849 1850 while (cbDMALeft) 1851 { 1852 void *pvBuf; size_t cbBuf; 1853 RTCircBufAcquireWriteBlock(pCircBuf, cbDMALeft, &pvBuf, &cbBuf); 1854 1855 if (cbBuf) 1856 { 1857 memcpy(pvBuf, pabFIFO + cbDMARead, cbBuf); 1858 cbDMARead += (uint32_t)cbBuf; 1859 cbDMALeft -= (uint32_t)cbBuf; 1860 #ifdef VBOX_WITH_DTRACE 1861 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBuf, pStreamR3->State.offWrite); 1862 #endif 1863 pStreamR3->State.offWrite += cbBuf; 1864 } 1865 1866 RTCircBufReleaseWriteBlock(pCircBuf, cbBuf); 1867 } 1868 } 1869 else 1870 { 1871 /* 1872 * The following code extracts the required audio stream (channel) data 1873 * of non-interleaved *and* interleaved audio streams. 1874 * 1875 * We by default only support 2 channels with 16-bit samples (HDA_FRAME_SIZE), 1876 * but an HDA audio stream can have interleaved audio data of multiple audio 1877 * channels in such a single stream ("AA,AA,AA vs. AA,BB,AA,BB"). 1878 * 1879 * So take this into account by just handling the first channel in such a stream ("A") 1880 * and just discard the other channel's data. 1881 * 1882 * I know, the following code is horribly slow, but seems to work for now. 1883 */ 1884 /** @todo Optimize channel data extraction! Use some SSE(3) / intrinsics? */ 1885 for (unsigned m = 0; m < pStreamR3->State.Mapping.cMappings; m++) 1886 { 1887 const uint32_t cbFrame = pStreamR3->State.Mapping.cbFrameSize; 1888 1889 Assert(cbFree >= cbDMA); 1890 1891 PPDMAUDIOSTREAMMAP pMap = &pStreamR3->State.Mapping.paMappings[m]; 1892 AssertPtr(pMap); 1893 1894 Log3Func(("Mapping #%u: Start (cbDMA=%RU32, cbFrame=%RU32, offNext=%RU32)\n", 1895 m, cbDMA, cbFrame, pMap->offNext)); 1896 1897 1898 /* Skip the current DMA chunk if the chunk is smaller than what the current stream mapping needs to read 1899 * the next associated frame (pointed to at pMap->cbOff). 1900 * 1901 * This can happen if the guest did not come up with enough data within a certain time period, especially 1902 * when using multi-channel speaker (> 2 channels [stereo]) setups. */ 1903 if (pMap->offNext > cbChunk) 1904 { 1905 Log2Func(("Mapping #%u: Skipped (cbChunk=%RU32, cbMapOff=%RU32)\n", m, cbChunk, pMap->offNext)); 1906 continue; 1907 } 1908 1909 uint8_t *pbSrcBuf = pabFIFO; 1910 size_t cbSrcOff = pMap->offNext; 1911 1912 for (unsigned i = 0; i < cbDMA / cbFrame; i++) 1913 { 1914 void *pvDstBuf; size_t cbDstBuf; 1915 RTCircBufAcquireWriteBlock(pCircBuf, pMap->cbStep, &pvDstBuf, &cbDstBuf); 1916 1917 Assert(cbDstBuf >= pMap->cbStep); 1918 1919 if (cbDstBuf) 1920 { 1921 Log3Func(("Mapping #%u: Frame #%02u: cbStep=%u, offFirst=%u, offNext=%u, cbDstBuf=%u, cbSrcOff=%u\n", 1922 m, i, pMap->cbStep, pMap->offFirst, pMap->offNext, cbDstBuf, cbSrcOff)); 1923 1924 memcpy(pvDstBuf, pbSrcBuf + cbSrcOff, cbDstBuf); 1925 1926 #if 0 /* Too slow, even for release builds, so disabled it. */ 1927 if (pStreamR3->Dbg.Runtime.fEnabled) 1928 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMAMapped, pvDstBuf, cbDstBuf, 1929 0 /* fFlags */); 1930 #endif 1931 Assert(cbSrcOff <= cbDMA); 1932 if (cbSrcOff + cbFrame + pMap->offFirst<= cbDMA) 1933 cbSrcOff += cbFrame + pMap->offFirst; 1934 1935 #ifdef VBOX_WITH_DTRACE 1936 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbDstBuf, pStreamR3->State.offWrite); 1937 #endif 1938 Log3Func(("Mapping #%u: Frame #%02u: -> cbSrcOff=%zu\n", m, i, cbSrcOff)); 1939 pStreamR3->State.offWrite += cbDstBuf; 1940 } 1941 1942 RTCircBufReleaseWriteBlock(pCircBuf, cbDstBuf); 1943 } 1944 1945 Log3Func(("Mapping #%u: End cbSize=%u, cbDMA=%RU32, cbSrcOff=%zu\n", 1946 m, pMap->cbStep, cbDMA, cbSrcOff)); 1947 1948 Assert(cbSrcOff <= cbDMA); 1949 1950 const uint32_t cbSrcLeft = cbDMA - (uint32_t)cbSrcOff; 1951 if (cbSrcLeft) 1952 { 1953 Log3Func(("Mapping #%u: cbSrcLeft=%RU32\n", m, cbSrcLeft)); 1954 1955 if (cbSrcLeft >= pMap->cbStep) 1956 { 1957 void *pvDstBuf; size_t cbDstBuf; 1958 RTCircBufAcquireWriteBlock(pCircBuf, pMap->cbStep, &pvDstBuf, &cbDstBuf); 1959 1960 Assert(cbDstBuf >= pMap->cbStep); 1961 1962 if (cbDstBuf) 1963 { 1964 memcpy(pvDstBuf, pbSrcBuf + cbSrcOff, cbDstBuf); 1965 #ifdef VBOX_WITH_DTRACE 1966 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbDstBuf, pStreamR3->State.offWrite); 1967 #endif 1968 pStreamR3->State.offWrite += cbDstBuf; 1969 } 1970 1971 RTCircBufReleaseWriteBlock(pCircBuf, cbDstBuf); 1972 } 1973 1974 Assert(pMap->cbFrame >= cbSrcLeft); 1975 pMap->offNext = pMap->cbFrame - cbSrcLeft; 1976 } 1977 else 1978 pMap->offNext = 0; 1979 1980 Log3Func(("Mapping #%u finish (cbSrcOff=%zu, offNext=%zu)\n", m, cbSrcOff, pMap->offNext)); 1981 } 1865 /* Grab internal DMA buffer space and read into it. */ 1866 void *pvBufDst; 1867 size_t cbBufDst; 1868 RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvBufDst, &cbBufDst); 1869 AssertBreakStmt(cbBufDst, RTCircBufReleaseWriteBlock(pCircBuf, 0)); 1870 1871 int rc2 = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBufDst, cbBufDst); 1872 AssertRC(rc2); 1873 1874 # ifdef HDA_DEBUG_SILENCE 1875 fix me if relevant; 1876 # endif 1877 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1878 { /* likely */ } 1879 else 1880 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */); 1881 1882 pStreamR3->State.offWrite += cbBufDst; 1883 RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst); 1884 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufDst); 1885 1886 /* advance */ 1887 cbChunk -= cbBufDst; 1888 GCPhys += cbBufDst; 1889 cbLeft -= cbBufDst; 1890 pBDLE->State.u32BufOff += cbBufDst; 1891 Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize); 1982 1892 } 1983 1893 } 1894 /* 1895 * Need to map the frame content, so we need to read the guest data 1896 * into a temporary buffer, though the output can be directly written 1897 * into the internal buffer as it is assumed to be frame aligned. 1898 * 1899 * Note! cbLeft is relative to the output frame size. 1900 * cbChunk OTOH is relative to input size. 1901 */ 1984 1902 else 1985 LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", uSD, rc)); 1903 { 1904 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft)); 1905 uint32_t const cbLeftInput = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, 1906 PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, 1907 cbLeft)); 1908 if (cbChunk <= cbLeftInput) 1909 { /* very likely */ } 1910 else 1911 cbChunk = cbLeftInput; 1912 1913 /* 1914 * Loop till we've covered the chunk. 1915 */ 1916 RTGCPHYS GCPhys = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff; 1917 Log5Func(("loop0: GCPhys=%RGp cbChunk=%#x + cbBounce=%#x\n", GCPhys, cbChunk, cbBounce)); 1918 while (cbChunk > 0) 1919 { 1920 /* Read into the bounce buffer. */ 1921 uint32_t const cbToRead = RT_MIN(cbChunk, sizeof(abBounce) - cbBounce); 1922 int rc2 = PDMDevHlpPhysRead(pDevIns, GCPhys, &abBounce[cbBounce], cbToRead); 1923 AssertRC(rc2); 1924 cbBounce += cbToRead; 1925 1926 /* Convert the size to whole frames and a remainder. */ 1927 uint32_t cFrames = PDMAudioPropsBytesToFrames(&pStreamR3->State.Mapping.GuestProps, cbBounce); 1928 uint32_t const cbRemainder = cbBounce - PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, cFrames); 1929 Log5Func((" loop1: GCPhys=%RGp cbToRead=%#x cbBounce=%#x cFrames=%#x\n", GCPhys, cbToRead, cbBounce, cFrames)); 1930 1931 /* 1932 * Convert from the bounce buffer and into the internal DMA buffer. 1933 */ 1934 uint32_t offBounce = 0; 1935 while (cFrames > 0) 1936 { 1937 void *pvBufDst; 1938 size_t cbBufDst; 1939 RTCircBufAcquireWriteBlock(pCircBuf, PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames), 1940 &pvBufDst, &cbBufDst); 1941 1942 uint32_t const cFramesToConvert = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbBufDst); 1943 Assert(PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFramesToConvert) == cbBufDst); 1944 Assert(cFramesToConvert > 0); 1945 Assert(cFramesToConvert <= cFrames); 1946 1947 pStreamR3->State.Mapping.pfnGuestToHost(pvBufDst, &abBounce[offBounce], cFramesToConvert, 1948 &pStreamR3->State.Mapping); 1949 Log5Func((" loop2: offBounce=%#05x cFramesToConvert=%#05x cbBufDst=%#x%s\n", 1950 offBounce, cFramesToConvert, cbBufDst, ASMMemIsZero(pvBufDst, cbBufDst) ? " all zero" : "")); 1951 1952 # ifdef HDA_DEBUG_SILENCE 1953 fix me if relevant; 1954 # endif 1955 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1956 { /* likely */ } 1957 else 1958 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */); 1959 1960 pStreamR3->State.offWrite += cbBufDst; 1961 RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst); 1962 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufDst); 1963 1964 /* advance */ 1965 cbLeft -= cbBufDst; 1966 cFrames -= cFramesToConvert; 1967 offBounce += PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, cFramesToConvert); 1968 } 1969 1970 /* advance */ 1971 cbChunk -= cbToRead; 1972 GCPhys += cbToRead; 1973 pBDLE->State.u32BufOff += cbToRead; 1974 Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize); 1975 if (cbRemainder) 1976 memmove(&abBounce[0], &abBounce[cbBounce - cbRemainder], cbRemainder); 1977 cbBounce = cbRemainder; 1978 } 1979 Log5Func(("loop0: GCPhys=%RGp cbBounce=%#x cbLeft=%#x\n", GCPhys, cbBounce, cbLeft)); 1980 } 1986 1981 1987 1982 STAM_PROFILE_STOP(&pThis->StatOut, a); 1988 1989 if (cbDMA)1990 {1991 /* We always increment the position of DMA buffer counter because we're always reading1992 * into an intermediate DMA buffer. */1993 pBDLE->State.u32BufOff += (uint32_t)cbDMA;1994 Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize);1995 1996 /* Are we done doing the position adjustment?1997 * Only then do the transfer accounting .*/1998 if (pStreamShared->State.cfPosAdjustLeft == 0)1999 {2000 Assert(cbLeft >= cbDMA);2001 cbLeft -= cbDMA;2002 }2003 2004 Log3Func(("[SD%RU8] cbDMA=%RU32 -> %R[bdle]\n", uSD, cbDMA, pBDLE));2005 }2006 1983 2007 1984 /* … … 2014 1991 /* Make sure to also update the wall clock when a BDLE is complete. 2015 1992 * Needed for Windows 10 guests. */ 1993 /** @todo there is a rounding error here. */ 2016 1994 hdaR3WalClkSet(pThis, pThisCC, 2017 1995 hdaWalClkGetCurrent(pThis) 2018 1996 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 2019 1997 pBDLE->Desc.u32BufSize 2020 / pStreamR3->State.Mapping.cb FrameSize),1998 / pStreamR3->State.Mapping.cbGuestFrame), 2021 1999 false /* fForce */); 2022 2000 … … 2033 2011 2034 2012 /* Does the current BDLE require an interrupt to be sent? */ 2035 if ( hdaR3BDLENeedsInterrupt(pBDLE) 2036 /* Are we done doing the position adjustment? 2037 * It can happen that a BDLE which is handled while doing the 2038 * position adjustment requires an interrupt on completion (IOC) being set. 2039 * 2040 * In such a case we need to skip such an interrupt and just move on. */ 2041 && pStreamShared->State.cfPosAdjustLeft == 0) 2013 if (hdaR3BDLENeedsInterrupt(pBDLE)) 2042 2014 { 2043 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set 2044 * we need to generate an interrupt. 2045 */ 2046 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE) 2015 if (cSuppressIocs == 0) 2047 2016 { 2048 /* Assert the interrupt before actually fetching the next BDLE below. */ 2049 if (!fInterruptSent) 2017 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL 2018 register is set we need to generate an interrupt. */ 2019 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE) 2050 2020 { 2051 #if 1 2052 pStreamShared->State.cTransferPendingInterrupts = 1; 2053 Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD)); 2054 #else 2055 /* ??*/ 2056 AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32, ("Too many pending interrupts (%RU8) for stream #%RU8\n", pStreamShared->State.cTransferPendingInterrupts, uSD)); 2057 Log3Func(("[SD%RU8] Scheduling interrupt (now %RU8 total)\n", uSD, pStreamShared->State.cTransferPendingInterrupts)); 2058 #endif 2059 2060 /* 2061 * Set the stream's BCIS bit. 2062 * 2063 * Note: This only must be done if the whole period is complete, and not if only 2064 * one specific BDL entry is complete (if it has the IOC bit set). 2065 * 2066 * This will otherwise confuses the guest when it 1) deasserts the interrupt, 2067 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 2068 * 2069 * snd_hda_intel on Linux will tell. 2070 */ 2071 /** @todo r=bird: The above comment does not match what we're doing. This is 2072 * just a flag indicating that the IOC is why the driver got an IRQ. */ 2073 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 2074 2075 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 2076 * ending / beginning a period. */ 2077 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 2078 2079 fInterruptSent = true; 2021 /* Assert the interrupt before actually fetching the next BDLE below. */ 2022 if (!fInterruptSent) 2023 { 2024 pStreamShared->State.cTransferPendingInterrupts = 1; 2025 Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD)); 2026 2027 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 2028 * ending / beginning of a period. */ 2029 /** @todo r=bird: What does the above comment mean? */ 2030 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 2031 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 2032 fInterruptSent = true; 2033 } 2080 2034 } 2081 2035 } 2036 else 2037 cSuppressIocs--; 2082 2038 } 2083 2039 2084 2040 /* 2085 * Advance .2041 * Advance to the next BDLE. 2086 2042 */ 2087 2043 if (pStreamShared->State.uCurBDLE >= pStreamShared->u16LVI) … … 2089 2045 else 2090 2046 pStreamShared->State.uCurBDLE++; 2091 2092 /* Fetch the next BDLE entry. */2093 2047 hdaR3BDLEFetch(pDevIns, pBDLE, pStreamShared->u64BDLBase, pStreamShared->State.uCurBDLE); 2094 2048 } 2095 2096 /* Do the position adjustment accounting. */ 2097 pStreamShared->State.cfPosAdjustLeft -= RT_MIN(pStreamShared->State.cfPosAdjustLeft, cbDMA / pStreamR3->State.Mapping.cbFrameSize); 2098 2099 if (RT_FAILURE(rc)) 2100 break; 2101 } 2102 2103 /* Remove the FIFORDY bit again. */ 2049 else 2050 Log3Func(("[SD%RU8] Not complete %R[bdle]\n", uSD, pBDLE)); 2051 } 2052 2053 Assert(cbLeft == 0); /* There shall be no break statements in the above loop, so cbLeft is always zero here! */ 2054 AssertMsg(cbBounce == 0, ("%#x\n", cbBounce)); 2055 2056 /* 2057 * Clear the (pointless) FIFORDY bit again. 2058 */ 2104 2059 HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY; 2105 2060 2106 /* Sanity. */ 2107 Assert(cbLeft == 0); 2108 uint32_t const cbProcessed = cbToProcessMax - cbLeft; 2109 2110 /* Only do the data accounting if we don't have to do any position 2111 * adjustment anymore. */ 2112 if (pStreamShared->State.cfPosAdjustLeft == 0) 2113 { 2114 hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbFrameSize, 2115 hdaR3StreamPeriodGetRemainingFrames(pPeriod))); 2116 } 2117 2118 const bool fTransferComplete = cbLeft == 0; 2119 if (fTransferComplete) 2120 { 2121 /* 2122 * Try updating the wall clock. 2123 * 2124 * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register 2125 * in order to determine the correct timing of the sound device. Other guests 2126 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely 2127 * ignore this. 2128 * 2129 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic 2130 * fashion) this *will* upset guest device drivers and will completely fuck up the 2131 * sound output. Running VLC on the guest will tell! 2132 */ 2133 const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, 2134 RT_MIN( hdaWalClkGetCurrent(pThis) 2135 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 2136 cbProcessed 2137 / pStreamR3->State.Mapping.cbFrameSize), 2138 hdaR3WalClkGetMax(pThis, pThisCC)), 2139 false /* fForce */); 2140 RT_NOREF(fWalClkSet); 2141 } 2142 2143 Log3Func(("[SD%RU8] %R[bdle] -- %#RX32/%#RX32 @ %#RX64 - fTransferComplete=%d (%d) cTransferPendingInterrupts=%RU8\n", 2144 uSD, pBDLE, cbProcessed, pStreamShared->State.cbTransferSize, pStreamR3->State.offWrite - cbProcessed, 2145 fTransferComplete, cbLeft, pStreamShared->State.cTransferPendingInterrupts)); 2061 /* 2062 * Try updating the wall clock. 2063 * 2064 * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register 2065 * in order to determine the correct timing of the sound device. Other guests 2066 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely 2067 * ignore this. 2068 * 2069 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic 2070 * fashion) this *will* upset guest device drivers and will completely fuck up the 2071 * sound output. Running VLC on the guest will tell! 2072 */ 2073 uint32_t const cFramesProcessed = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbToProduce); 2074 /** @todo this needs to go, but we need it for hdaR3WalClkGetMax below. */ 2075 hdaR3StreamPeriodInc(&pStreamShared->State.Period, 2076 RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period))); 2077 2078 uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(pPeriod, cFramesProcessed); 2079 uint64_t const uWallNew = hdaWalClkGetCurrent(pThis) + cWallTicks; 2080 uint64_t const uWallMax = hdaR3WalClkGetMax(pThis, pThisCC); 2081 bool const fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, RT_MIN(uWallNew, uWallMax), false /* fForce */); 2082 RT_NOREF(fWalClkSet); 2083 2084 /* 2085 * Log and leave. 2086 */ 2087 Log3Func(("[SD%RU8] %R[bdle] -- %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n", 2088 uSD, pBDLE, cbToProduce, pStreamShared->State.cbTransferSize, pStreamR3->State.offWrite - cbToProduce, 2089 pStreamShared->State.cTransferPendingInterrupts)); 2146 2090 2147 2091 LogFlowFuncLeave(); … … 2164 2108 uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable); 2165 2109 /* Make sure that we always align the number of bytes when reading to the stream's PCM properties. */ 2166 cbToReadFromStream = PDMAudioPropsFloorBytesToFrame(&pStream R3->State.Mapping.PCMProps, cbToReadFromStream);2110 cbToReadFromStream = PDMAudioPropsFloorBytesToFrame(&pStreamShared->State.Cfg.Props, cbToReadFromStream); 2167 2111 2168 2112 Assert(nsNow >= pStreamShared->State.tsLastReadNs); … … 2205 2149 2206 2150 /* Re-arm the timer if the sink is still active: */ 2207 if ( pStreamR3->pMixSink 2151 if ( pStreamShared->State.fRunning 2152 && pStreamR3->pMixSink 2208 2153 && AudioMixerSinkIsActive(pStreamR3->pMixSink->pMixSink)) 2209 2154 { -
trunk/src/VBox/Devices/Audio/HDAStream.h
r88094 r88112 132 132 * Can be 0 if no next transfer is scheduled. */ 133 133 uint64_t tsTransferNext; 134 /** Total transfer size (in bytes) of a transfer period. */ 134 /** Total transfer size (in bytes) of a transfer period. 135 * @note This is in host side frames, in case we're doing any mapping. */ 135 136 uint32_t cbTransferSize; 136 /** Transfer chunk size (in bytes) of a transfer period. */137 /** Unused, same as cbTransferSize. */ 137 138 uint32_t cbTransferChunk; 138 139 /** How many interrupts are pending due to … … 157 158 /** The stream's period. Need for timing. */ 158 159 HDASTREAMPERIOD Period; 159 /** The stream's current configuration. 160 * Should match SDFMT. */ 160 /** The stream's current host side configuration. 161 * This should match the SDnFMT in all respects but maybe the channel count as 162 * we may need to expand mono or into/from into stereo. The unmodified SDnFMT 163 * properties can be found in HDASTREAMR3::Mapping::PCMProps. */ 161 164 PDMAUDIOSTREAMCFG Cfg; 162 165 /** Timestamp (real time, in ns) of last DMA transfer. */ -
trunk/src/VBox/Devices/Audio/HDAStreamMap.cpp
r88028 r88112 23 23 #include <VBox/log.h> 24 24 25 #include <iprt/mem.h>26 27 25 #include <VBox/vmm/pdmdev.h> 28 26 #include <VBox/vmm/pdmaudioifs.h> 29 27 #include <VBox/vmm/pdmaudioinline.h> 30 28 29 #include <iprt/mem.h> 30 #include <iprt/string.h> 31 31 32 #include "DrvAudio.h" 32 33 … … 34 35 #include "HDAStreamMap.h" 35 36 36 #ifdef IN_RING3 37 38 static int hdaR3StreamMapSetup(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps); 39 40 /** 41 * Initializes a stream mapping structure according to the given PCM properties. 42 * 43 * @return IPRT status code. 44 * @param pMap Pointer to mapping to initialize. 45 * @param pProps Pointer to PCM properties to use for initialization. 46 */ 47 int hdaR3StreamMapInit(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps) 48 { 49 AssertPtrReturn(pMap, VERR_INVALID_POINTER); 50 AssertPtrReturn(pProps, VERR_INVALID_POINTER); 51 52 if (!DrvAudioHlpPcmPropsAreValid(pProps)) 53 return VERR_INVALID_PARAMETER; 54 55 hdaR3StreamMapReset(pMap); 56 57 int rc = hdaR3StreamMapSetup(pMap, pProps); 58 if (RT_FAILURE(rc)) 59 return rc; 60 61 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 62 if ( RT_SUCCESS(rc) 63 /* Create circular buffer if not created yet. */ 64 && !pMap->pCircBuf) 65 { 66 rc = RTCircBufCreate(&pMap->pCircBuf, _4K); /** @todo Make size configurable? */ 67 } 68 #endif 69 70 if (RT_SUCCESS(rc)) 71 { 72 pMap->cbFrameSize = pProps->cChannels * pProps->cbSample; 73 74 LogFunc(("cChannels=%RU8, cBytes=%RU8 -> cbFrameSize=%RU32\n", 75 pProps->cChannels, pProps->cbSample, pMap->cbFrameSize)); 76 77 Assert(pMap->cbFrameSize); /* Frame size must not be 0. */ 78 79 pMap->enmLayout = PDMAUDIOSTREAMLAYOUT_INTERLEAVED; 80 } 81 82 return rc; 83 } 84 85 86 /** 87 * Destroys a given stream mapping. 88 * 89 * @param pMap Pointer to mapping to destroy. 90 */ 91 void hdaR3StreamMapDestroy(PHDASTREAMMAP pMap) 92 { 93 hdaR3StreamMapReset(pMap); 94 95 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 96 if (pMap->pCircBuf) 97 { 98 RTCircBufDestroy(pMap->pCircBuf); 99 pMap->pCircBuf = NULL; 100 } 101 #endif 102 } 103 104 105 /** 106 * Resets a given stream mapping. 107 * 108 * @param pMap Pointer to mapping to reset. 109 */ 110 void hdaR3StreamMapReset(PHDASTREAMMAP pMap) 111 { 112 AssertPtrReturnVoid(pMap); 113 114 pMap->enmLayout = PDMAUDIOSTREAMLAYOUT_UNKNOWN; 115 116 if (pMap->paMappings) 117 { 118 for (uint8_t i = 0; i < pMap->cMappings; i++) 119 hdaR3StreamChannelDataDestroy(&pMap->paMappings[i].Data); 120 121 RTMemFree(pMap->paMappings); 122 pMap->paMappings = NULL; 123 124 pMap->cMappings = 0; 125 } 126 127 RT_ZERO(pMap->PCMProps); 37 38 39 /** Convert host stereo to mono guest, signed 16-bit edition. */ 40 static DECLCALLBACK(void) 41 hdaR3StreamMap_H2G_GenericS16_Stereo2Mono(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 42 { 43 /** @todo this doesn't merge the two, it just picks the first one. */ 44 uint16_t *pu16Dst = (uint16_t *)pvDst; 45 uint16_t const *pu16Src = (uint16_t const *)pvSrc; 46 size_t const cbDstFrame = pMap->cbGuestFrame; 47 48 if (cbDstFrame != sizeof(*pu16Dst)) 49 RT_BZERO(pvDst, cbDstFrame * cFrames); 50 51 while (cFrames-- > 0) 52 { 53 *pu16Dst = *pu16Src; 54 pu16Src += 2; 55 pu16Dst = (uint16_t *)((uintptr_t)pu16Dst + cbDstFrame); 56 } 57 } 58 59 60 /** Convert mono guest channel to host stereo, signed 16-bit edition. */ 61 static DECLCALLBACK(void) 62 hdaR3StreamMap_G2H_GenericS16_Mono2Stereo(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 63 { 64 uint32_t *pu32Dst = (uint32_t *)pvDst; 65 uint16_t const *pu16Src = (uint16_t const *)pvSrc; 66 size_t const cbSrcFrame = pMap->cbGuestFrame; 67 68 while (cFrames-- > 0) 69 { 70 uint16_t uSample = *pu16Src; 71 *pu32Dst++ = RT_MAKE_U32(uSample, uSample); 72 pu16Src = (uint16_t const *)((uintptr_t)pu16Src + cbSrcFrame); 73 } 74 } 75 76 77 /** Convert host stereo to mono guest, signed 32-bit edition. */ 78 static DECLCALLBACK(void) 79 hdaR3StreamMap_H2G_GenericS32_Stereo2Mono(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 80 { 81 /** @todo this doesn't merge the two, it just picks the first one. */ 82 uint32_t *pu32Dst = (uint32_t *)pvDst; 83 uint32_t const *pu32Src = (uint32_t const *)pvSrc; 84 size_t const cbDstFrame = pMap->cbGuestFrame; 85 86 if (cbDstFrame != sizeof(*pu32Dst)) 87 RT_BZERO(pvDst, cbDstFrame * cFrames); 88 89 while (cFrames-- > 0) 90 { 91 *pu32Dst = *pu32Src; 92 pu32Src += 2; 93 pu32Dst = (uint32_t *)((uintptr_t)pu32Dst + cbDstFrame); 94 } 95 } 96 97 98 /** Convert mono guest channel to host stereo, signed 32-bit edition. */ 99 static DECLCALLBACK(void) 100 hdaR3StreamMap_G2H_GenericS32_Mono2Stereo(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 101 { 102 uint64_t *pu64Dst = (uint64_t *)pvDst; 103 uint32_t const *pu32Src = (uint32_t const *)pvSrc; 104 size_t const cbSrcFrame = pMap->cbGuestFrame; 105 106 while (cFrames-- > 0) 107 { 108 uint32_t uSample = *pu32Src; 109 *pu64Dst++ = RT_MAKE_U64(uSample, uSample); 110 pu32Src = (uint32_t const *)((uintptr_t)pu32Src + cbSrcFrame); 111 } 112 } 113 114 115 /** Convert stereo host to 2 or more guest channels, signed 16-bit edition. */ 116 static DECLCALLBACK(void) 117 hdaR3StreamMap_H2G_GenericS16_Stereo2NonMono(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 118 { 119 uint32_t *pu32Dst = (uint32_t *)pvDst; 120 uint32_t const *pu32Src = (uint32_t const *)pvSrc; /** @todo could be misaligned */ 121 size_t const cbDstFrame = pMap->cbGuestFrame; 122 123 RT_BZERO(pvDst, cbDstFrame * cFrames); 124 125 while (cFrames-- > 0) 126 { 127 *pu32Dst = *pu32Src++; 128 pu32Dst = (uint32_t *)((uintptr_t)pu32Dst + cbDstFrame); 129 } 130 } 131 132 133 /** Convert 2 or more guest channels to host stereo, signed 16-bit edition. */ 134 static DECLCALLBACK(void) 135 hdaR3StreamMap_G2H_GenericS16_NonMono2Stereo(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 136 { 137 uint32_t *pu32Dst = (uint32_t *)pvDst; 138 uint32_t const *pu32Src = (uint32_t const *)pvSrc; /** @todo could be misaligned */ 139 size_t const cbSrcFrame = pMap->cbGuestFrame; 140 141 while (cFrames-- > 0) 142 { 143 *pu32Dst++ = *pu32Src; 144 pu32Src = (uint32_t const *)((uintptr_t)pu32Src + cbSrcFrame); 145 } 146 } 147 148 149 /** Convert stereo host to 2 or more guest channels, signed 32-bit edition. */ 150 static DECLCALLBACK(void) 151 hdaR3StreamMap_H2G_GenericS32_Stereo2NonMono(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 152 { 153 uint64_t *pu64Dst = (uint64_t *)pvDst; /** @todo could be misaligned. */ 154 uint64_t const *pu64Src = (uint64_t const *)pvSrc; 155 size_t const cbDstFrame = pMap->cbGuestFrame; 156 157 RT_BZERO(pvDst, cbDstFrame * cFrames); 158 159 while (cFrames-- > 0) 160 { 161 *pu64Dst = *pu64Src++; 162 pu64Dst = (uint64_t *)((uintptr_t)pu64Dst + cbDstFrame); 163 } 164 } 165 166 167 /** Convert 2 or more guest channels to host stereo, signed 32-bit edition. */ 168 static DECLCALLBACK(void) 169 hdaR3StreamMap_G2H_GenericS32_NonMono2Stereo(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 170 { 171 uint64_t *pu64Dst = (uint64_t *)pvDst; 172 uint64_t const *pu64Src = (uint64_t const *)pvSrc; /** @todo could be misaligned */ 173 size_t const cbSrcFrame = pMap->cbGuestFrame; 174 175 while (cFrames-- > 0) 176 { 177 *pu64Dst++ = *pu64Src; 178 pu64Src = (uint64_t const *)((uintptr_t)pu64Src + cbSrcFrame); 179 } 180 } 181 182 183 /** No conversion needed, just copy the data. */ 184 static DECLCALLBACK(void) 185 hdaR3StreamMap_GenericCopy(void *pvDst, void const *pvSrc, uint32_t cFrames, HDASTREAMMAP const *pMap) 186 { 187 memcpy(pvDst, pvSrc, cFrames * pMap->cbGuestFrame); 128 188 } 129 189 … … 132 192 * Sets up a stream mapping according to the given properties / configuration. 133 193 * 134 * @return VBox status code, or VERR_NOT_SUPPORTED if the channel setup is not supported (yet). 135 * @param pMap Pointer to mapping to set up. 136 * @param pProps PCM audio properties to use for lookup. 137 */ 138 static int hdaR3StreamMapSetup(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps) 194 * @return VBox status code. 195 * @retval VERR_NOT_SUPPORTED if the channel setup is not supported. 196 * 197 * @param pMap Pointer to mapping to set up. 198 * @param pProps Input: The stream PCM properties from the guest. 199 * Output: Properties for the host stream. 200 * @param cHostChannels The number of host channels to map to. 201 */ 202 static int hdaR3StreamMapSetup(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps, uint8_t cHostChannels) 139 203 { 140 204 int rc; … … 150 214 || pProps->cChannels == 6) /* Surround (5.1) */ 151 215 { 216 /* 217 * Copy the guest stream properties and see if we need to change the host properties. 218 */ 219 memcpy(&pMap->GuestProps, pProps, sizeof(PDMAUDIOPCMPROPS)); 220 if (pProps->cChannels != cHostChannels) 221 { 222 if (pProps->cChannels == 1) 223 LogRelMax(32, ("HDA: Warning: Guest mono, host stereo.\n")); 224 else if (cHostChannels == 1 && pProps->cChannels == 2) 225 LogRelMax(32, ("HDA: Warning: Host mono, guest stereo.\n")); 226 else 227 #ifndef VBOX_WITH_AUDIO_HDA_51_SURROUND 228 LogRelMax(32, ("HDA: Warning: Guest configured %u channels, host only supports %u. Ignoring additional channels.\n", 229 pProps->cChannels, cHostChannels)); 230 #else 231 # error reconsider the above logic 232 #endif 233 pProps->cChannels = cHostChannels; 234 pProps->cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps); 235 } 236 237 /* 238 * Pick conversion functions. 239 */ 240 Assert(pMap->GuestProps.cbSample == pProps->cbSample); 241 242 /* If the channel count matches, we can use the memcpy converters: */ 243 if (pProps->cChannels == pMap->GuestProps.cChannels) 244 { 245 pMap->pfnGuestToHost = hdaR3StreamMap_GenericCopy; 246 pMap->pfnHostToGuest = hdaR3StreamMap_GenericCopy; 247 pMap->fMappingNeeded = false; 248 } 249 else 250 { 251 /* For multi-speaker guest configs, we currently just pick the 252 first two channels and map this onto the host stereo ones. */ 253 AssertReturn(cHostChannels == 2, VERR_NOT_SUPPORTED); 254 switch (pMap->GuestProps.cbSample) 255 { 256 case 2: 257 if (pMap->GuestProps.cChannels > 1) 258 { 259 pMap->pfnGuestToHost = hdaR3StreamMap_G2H_GenericS16_NonMono2Stereo; 260 pMap->pfnHostToGuest = hdaR3StreamMap_H2G_GenericS16_Stereo2NonMono; 261 } 262 else 263 { 264 pMap->pfnGuestToHost = hdaR3StreamMap_G2H_GenericS16_Mono2Stereo; 265 pMap->pfnHostToGuest = hdaR3StreamMap_H2G_GenericS16_Stereo2Mono; 266 } 267 break; 268 269 case 4: 270 if (pMap->GuestProps.cChannels > 1) 271 { 272 pMap->pfnGuestToHost = hdaR3StreamMap_G2H_GenericS32_NonMono2Stereo; 273 pMap->pfnHostToGuest = hdaR3StreamMap_H2G_GenericS32_Stereo2NonMono; 274 } 275 else 276 { 277 pMap->pfnGuestToHost = hdaR3StreamMap_G2H_GenericS32_Mono2Stereo; 278 pMap->pfnHostToGuest = hdaR3StreamMap_H2G_GenericS32_Stereo2Mono; 279 } 280 break; 281 282 default: 283 AssertMsgFailedReturn(("cbSample=%u\n", pMap->GuestProps.cbSample), VERR_NOT_SUPPORTED); 284 } 285 pMap->fMappingNeeded = true; 286 } 287 288 /** @todo bird: Not sure if this is really needed any more. */ 289 152 290 /* For now we don't have anything other as mono / stereo channels being covered by the backends. 153 291 * So just set up one channel covering those and skipping the rest (like configured rear or center/LFE outputs). */ 154 292 pMap->cMappings = 1; 155 293 pMap->paMappings = (PPDMAUDIOSTREAMMAP)RTMemAlloc(sizeof(PDMAUDIOSTREAMMAP) * pMap->cMappings); 156 if (!pMap->paMappings) 157 return VERR_NO_MEMORY; 158 159 PPDMAUDIOSTREAMMAP pMapLR = &pMap->paMappings[0]; 160 161 pMapLR->aenmIDs[0] = PDMAUDIOSTREAMCHANNELID_FRONT_LEFT; 162 pMapLR->aenmIDs[1] = PDMAUDIOSTREAMCHANNELID_FRONT_RIGHT; 163 pMapLR->cbFrame = pProps->cbSample * pProps->cChannels; 164 pMapLR->cbStep = pProps->cbSample * 2 /* Front left + Front right channels */; 165 pMapLR->offFirst = 0; 166 pMapLR->offNext = pMapLR->offFirst; 167 168 rc = hdaR3StreamChannelDataInit(&pMapLR->Data, PDMAUDIOSTREAMCHANNELDATA_FLAGS_NONE); 169 AssertRC(rc); 170 171 memcpy(&pMap->PCMProps, pProps, sizeof(PDMAUDIOPCMPROPS)); 294 if (pMap->paMappings) 295 { 296 PPDMAUDIOSTREAMMAP pMapLR = &pMap->paMappings[0]; 297 pMapLR->aenmIDs[0] = PDMAUDIOSTREAMCHANNELID_FRONT_LEFT; 298 pMapLR->aenmIDs[1] = PDMAUDIOSTREAMCHANNELID_FRONT_RIGHT; 299 pMapLR->cbFrame = pProps->cbSample * pProps->cChannels; 300 pMapLR->cbStep = pProps->cbSample * 2 /* Front left + Front right channels */; 301 pMapLR->offFirst = 0; 302 pMapLR->offNext = pMapLR->offFirst; 303 304 rc = hdaR3StreamChannelDataInit(&pMapLR->Data, PDMAUDIOSTREAMCHANNELDATA_FLAGS_NONE); 305 AssertRC(rc); 306 } 307 else 308 rc = VERR_NO_MEMORY; 172 309 } 173 310 else … … 176 313 return rc; 177 314 } 178 #endif /* IN_RING3 */ 179 315 316 317 /** 318 * Initializes a stream mapping structure according to the given PCM properties. 319 * 320 * @return IPRT status code. 321 * @param pMap Pointer to mapping to initialize. 322 * @param cHostChannels The number of host channels to map to. 323 * @param pProps Input: The stream PCM properties from the guest. 324 * Output: Properties for the host side. 325 */ 326 int hdaR3StreamMapInit(PHDASTREAMMAP pMap, uint8_t cHostChannels, PPDMAUDIOPCMPROPS pProps) 327 { 328 AssertPtrReturn(pMap, VERR_INVALID_POINTER); 329 AssertPtrReturn(pProps, VERR_INVALID_POINTER); 330 331 if (!DrvAudioHlpPcmPropsAreValid(pProps)) 332 return VERR_INVALID_PARAMETER; 333 334 hdaR3StreamMapReset(pMap); 335 336 pMap->cbGuestFrame = pProps->cChannels * pProps->cbSample; 337 int rc = hdaR3StreamMapSetup(pMap, pProps, cHostChannels); 338 if (RT_SUCCESS(rc)) 339 { 340 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 341 /* Create the circular buffer if not created yet. */ 342 if (!pMap->pCircBuf) 343 rc = RTCircBufCreate(&pMap->pCircBuf, _4K); /** @todo Make size configurable? */ 344 if (RT_SUCCESS(rc)) 345 #endif 346 { 347 LogFunc(("cChannels=%RU8, cBytes=%RU8 -> cbGuestFrame=%RU32\n", 348 pProps->cChannels, pProps->cbSample, pMap->cbGuestFrame)); 349 350 Assert(pMap->cbGuestFrame); /* Frame size must not be 0. */ 351 pMap->enmLayout = PDMAUDIOSTREAMLAYOUT_INTERLEAVED; 352 return VINF_SUCCESS; 353 } 354 } 355 356 return rc; 357 } 358 359 360 /** 361 * Destroys a given stream mapping. 362 * 363 * @param pMap Pointer to mapping to destroy. 364 */ 365 void hdaR3StreamMapDestroy(PHDASTREAMMAP pMap) 366 { 367 hdaR3StreamMapReset(pMap); 368 369 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 370 if (pMap->pCircBuf) 371 { 372 RTCircBufDestroy(pMap->pCircBuf); 373 pMap->pCircBuf = NULL; 374 } 375 #endif 376 } 377 378 379 /** 380 * Resets a given stream mapping. 381 * 382 * @param pMap Pointer to mapping to reset. 383 */ 384 void hdaR3StreamMapReset(PHDASTREAMMAP pMap) 385 { 386 AssertPtrReturnVoid(pMap); 387 388 pMap->enmLayout = PDMAUDIOSTREAMLAYOUT_UNKNOWN; 389 390 if (pMap->paMappings) 391 { 392 for (uint8_t i = 0; i < pMap->cMappings; i++) 393 hdaR3StreamChannelDataDestroy(&pMap->paMappings[i].Data); 394 395 RTMemFree(pMap->paMappings); 396 pMap->paMappings = NULL; 397 398 pMap->cMappings = 0; 399 } 400 401 pMap->fMappingNeeded = false; 402 pMap->pfnGuestToHost = hdaR3StreamMap_GenericCopy; 403 pMap->pfnHostToGuest = hdaR3StreamMap_GenericCopy; 404 RT_ZERO(pMap->GuestProps); 405 } 406 -
trunk/src/VBox/Devices/Audio/HDAStreamMap.h
r87942 r88112 27 27 typedef struct HDASTREAMMAP 28 28 { 29 /** The PCM properties which have been used. */ 30 PDMAUDIOPCMPROPS PCMProps; 29 /** The guest stream properties that is being mapped from/to. 30 * The host properties are found in HDASTREAMSTATE::Cfg::Props. */ 31 PDMAUDIOPCMPROPS GuestProps; 31 32 /** The stream's layout. */ 32 33 PDMAUDIOSTREAMLAYOUT enmLayout; 33 /** The mapping's overall audio frame size (in bytes). 34 * This includes all mappings in \a paMappings. */ 35 uint8_t cbFrameSize; 34 /** The guest side frame size in bytes. */ 35 uint8_t cbGuestFrame; 36 /** Set if mapping is needed. */ 37 bool fMappingNeeded; 36 38 /** Number of mappings in paMappings. */ 37 39 uint8_t cMappings; 38 uint8_t aPadding[ 2];40 uint8_t aPadding[1]; 39 41 /** Array of stream mappings. 40 42 * Note: The mappings *must* be layed out in an increasing order, e.g. … … 48 50 R3PTRTYPE(PRTCIRCBUF) pCircBuf; 49 51 #endif 52 /** 53 * Converts guest data to host data. 54 * 55 * @param pvDst The destination (host) buffer. 56 * @param pvSrc The source (guest) data. Does not overlap @a pvDst. 57 * @param cFrames Number of frames to convert. 58 * @param pMapping Pointer to this structure. 59 */ 60 DECLCALLBACKMEMBER(void, pfnGuestToHost,(void *pvDst, void const *pvSrc, uint32_t cFrames, 61 struct HDASTREAMMAP const *pMapping)); 62 /** 63 * Converts host data to guest data. 64 * 65 * @param pvDst The destination (guest) buffer. 66 * @param pvSrc The source (host) data. Does not overlap @a pvDst. 67 * @param cFrames Number of frames to convert. 68 * @param pMapping Pointer to this structure. 69 */ 70 DECLCALLBACKMEMBER(void, pfnHostToGuest,(void *pvDst, void const *pvSrc, uint32_t cFrames, 71 struct HDASTREAMMAP const *pMapping)); 50 72 } HDASTREAMMAP; 51 73 AssertCompileSizeAlignment(HDASTREAMMAP, 8); … … 57 79 */ 58 80 #ifdef IN_RING3 59 int hdaR3StreamMapInit(PHDASTREAMMAP pMapping, PPDMAUDIOPCMPROPS pProps);81 int hdaR3StreamMapInit(PHDASTREAMMAP pMapping, uint8_t cHostChannels, PPDMAUDIOPCMPROPS pProps); 60 82 void hdaR3StreamMapDestroy(PHDASTREAMMAP pMapping); 61 83 void hdaR3StreamMapReset(PHDASTREAMMAP pMapping); -
trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
r88028 r88112 38 38 RTTestSub(hTest, "Basics"); 39 39 40 static const PDMAUDIOPCMPROPS s_Cfg441StereoS16 = PDMAUDIOPCMPROPS_INITIALIZOR(40 const PDMAUDIOPCMPROPS Cfg441StereoS16 = PDMAUDIOPCMPROPS_INITIALIZOR( 41 41 /* a_cb: */ 2, 42 42 /* a_fSigned: */ true, … … 46 46 /* a_fSwapEndian: */ false 47 47 ); 48 static const PDMAUDIOPCMPROPS s_Cfg441StereoU16 = PDMAUDIOPCMPROPS_INITIALIZOR(48 const PDMAUDIOPCMPROPS Cfg441StereoU16 = PDMAUDIOPCMPROPS_INITIALIZOR( 49 49 /* a_cb: */ 2, 50 50 /* a_fSigned: */ false, … … 54 54 /* a_fSwapEndian: */ false 55 55 ); 56 static const PDMAUDIOPCMPROPS s_Cfg441StereoU32 = PDMAUDIOPCMPROPS_INITIALIZOR(56 const PDMAUDIOPCMPROPS Cfg441StereoU32 = PDMAUDIOPCMPROPS_INITIALIZOR( 57 57 /* a_cb: */ 4, 58 58 /* a_fSigned: */ false, … … 63 63 ); 64 64 65 RTTESTI_CHECK(PDMAudioPropsGetBitrate(& s_Cfg441StereoS16) == 44100*4*8);66 RTTESTI_CHECK(PDMAudioPropsGetBitrate(& s_Cfg441StereoU16) == 44100*4*8);67 RTTESTI_CHECK(PDMAudioPropsGetBitrate(& s_Cfg441StereoU32) == 44100*8*8);68 69 RTTESTI_CHECK(DrvAudioHlpPcmPropsAreValid(& s_Cfg441StereoS16));70 RTTESTI_CHECK(DrvAudioHlpPcmPropsAreValid(& s_Cfg441StereoU16) == false); /* go figure */71 RTTESTI_CHECK(DrvAudioHlpPcmPropsAreValid(& s_Cfg441StereoU32) == false); /* go figure */72 73 74 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(& s_Cfg441StereoS16, 1) == 4,75 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(& s_Cfg441StereoS16, 1)));76 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(& s_Cfg441StereoU16, 1) == 4,77 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(& s_Cfg441StereoU16, 1)));78 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(& s_Cfg441StereoU32, 1) == 8,79 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(& s_Cfg441StereoU32, 1)));80 81 RTTESTI_CHECK_MSG(PDMAudioPropsBytesPerFrame(& s_Cfg441StereoS16) == 4,82 ("got %x, expected 4\n", PDMAudioPropsBytesPerFrame(& s_Cfg441StereoS16)));83 RTTESTI_CHECK_MSG(PDMAudioPropsBytesPerFrame(& s_Cfg441StereoU16) == 4,84 ("got %x, expected 4\n", PDMAudioPropsBytesPerFrame(& s_Cfg441StereoU16)));85 RTTESTI_CHECK_MSG(PDMAudioPropsBytesPerFrame(& s_Cfg441StereoU32) == 8,86 ("got %x, expected 4\n", PDMAudioPropsBytesPerFrame(& s_Cfg441StereoU32)));65 RTTESTI_CHECK(PDMAudioPropsGetBitrate(&Cfg441StereoS16) == 44100*4*8); 66 RTTESTI_CHECK(PDMAudioPropsGetBitrate(&Cfg441StereoU16) == 44100*4*8); 67 RTTESTI_CHECK(PDMAudioPropsGetBitrate(&Cfg441StereoU32) == 44100*8*8); 68 69 RTTESTI_CHECK(DrvAudioHlpPcmPropsAreValid(&Cfg441StereoS16)); 70 RTTESTI_CHECK(DrvAudioHlpPcmPropsAreValid(&Cfg441StereoU16) == false); /* go figure */ 71 RTTESTI_CHECK(DrvAudioHlpPcmPropsAreValid(&Cfg441StereoU32) == false); /* go figure */ 72 73 74 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(&Cfg441StereoS16, 1) == 4, 75 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(&Cfg441StereoS16, 1))); 76 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(&Cfg441StereoU16, 1) == 4, 77 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(&Cfg441StereoU16, 1))); 78 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(&Cfg441StereoU32, 1) == 8, 79 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(&Cfg441StereoU32, 1))); 80 81 RTTESTI_CHECK_MSG(PDMAudioPropsBytesPerFrame(&Cfg441StereoS16) == 4, 82 ("got %x, expected 4\n", PDMAudioPropsBytesPerFrame(&Cfg441StereoS16))); 83 RTTESTI_CHECK_MSG(PDMAudioPropsBytesPerFrame(&Cfg441StereoU16) == 4, 84 ("got %x, expected 4\n", PDMAudioPropsBytesPerFrame(&Cfg441StereoU16))); 85 RTTESTI_CHECK_MSG(PDMAudioPropsBytesPerFrame(&Cfg441StereoU32) == 8, 86 ("got %x, expected 4\n", PDMAudioPropsBytesPerFrame(&Cfg441StereoU32))); 87 87 88 88 uint32_t u32; 89 89 for (uint32_t i = 0; i < 256; i += 8) 90 90 { 91 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(& s_Cfg441StereoU32, i) == true);91 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(&Cfg441StereoU32, i) == true); 92 92 for (uint32_t j = 1; j < 8; j++) 93 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(& s_Cfg441StereoU32, i + j) == false);93 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(&Cfg441StereoU32, i + j) == false); 94 94 for (uint32_t j = 0; j < 8; j++) 95 RTTESTI_CHECK(PDMAudioPropsFloorBytesToFrame(& s_Cfg441StereoU32, i + j) == i);95 RTTESTI_CHECK(PDMAudioPropsFloorBytesToFrame(&Cfg441StereoU32, i + j) == i); 96 96 } 97 97 for (uint32_t i = 0; i < 4096; i += 4) 98 98 { 99 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(& s_Cfg441StereoS16, i) == true);99 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(&Cfg441StereoS16, i) == true); 100 100 for (uint32_t j = 1; j < 4; j++) 101 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(& s_Cfg441StereoS16, i + j) == false);101 RTTESTI_CHECK(PDMAudioPropsIsSizeAligned(&Cfg441StereoS16, i + j) == false); 102 102 for (uint32_t j = 0; j < 4; j++) 103 RTTESTI_CHECK(PDMAudioPropsFloorBytesToFrame(& s_Cfg441StereoS16, i + j) == i);104 } 105 106 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(& s_Cfg441StereoS16, 44100)) == 44100 * 2 * 2,103 RTTESTI_CHECK(PDMAudioPropsFloorBytesToFrame(&Cfg441StereoS16, i + j) == i); 104 } 105 106 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(&Cfg441StereoS16, 44100)) == 44100 * 2 * 2, 107 107 ("cb=%RU32\n", u32)); 108 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(& s_Cfg441StereoS16, 2)) == 2 * 2 * 2,108 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(&Cfg441StereoS16, 2)) == 2 * 2 * 2, 109 109 ("cb=%RU32\n", u32)); 110 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(& s_Cfg441StereoS16, 1)) == 4,110 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(&Cfg441StereoS16, 1)) == 4, 111 111 ("cb=%RU32\n", u32)); 112 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(& s_Cfg441StereoU16, 1)) == 4,112 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(&Cfg441StereoU16, 1)) == 4, 113 113 ("cb=%RU32\n", u32)); 114 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(& s_Cfg441StereoU32, 1)) == 8,114 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsFramesToBytes(&Cfg441StereoU32, 1)) == 8, 115 115 ("cb=%RU32\n", u32)); 116 116 117 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsBytesToFrames(& s_Cfg441StereoS16, 4)) == 1, ("cb=%RU32\n", u32));118 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsBytesToFrames(& s_Cfg441StereoU16, 4)) == 1, ("cb=%RU32\n", u32));119 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsBytesToFrames(& s_Cfg441StereoU32, 8)) == 1, ("cb=%RU32\n", u32));117 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsBytesToFrames(&Cfg441StereoS16, 4)) == 1, ("cb=%RU32\n", u32)); 118 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsBytesToFrames(&Cfg441StereoU16, 4)) == 1, ("cb=%RU32\n", u32)); 119 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsBytesToFrames(&Cfg441StereoU32, 8)) == 1, ("cb=%RU32\n", u32)); 120 120 121 121 uint64_t u64; 122 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsBytesToNano(& s_Cfg441StereoS16, 44100 * 2 * 2)) == RT_NS_1SEC,122 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsBytesToNano(&Cfg441StereoS16, 44100 * 2 * 2)) == RT_NS_1SEC, 123 123 ("ns=%RU64\n", u64)); 124 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsBytesToMicro(& s_Cfg441StereoS16, 44100 * 2 * 2)) == RT_US_1SEC,124 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsBytesToMicro(&Cfg441StereoS16, 44100 * 2 * 2)) == RT_US_1SEC, 125 125 ("us=%RU64\n", u64)); 126 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsBytesToMilli(& s_Cfg441StereoS16, 44100 * 2 * 2)) == RT_MS_1SEC,126 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsBytesToMilli(&Cfg441StereoS16, 44100 * 2 * 2)) == RT_MS_1SEC, 127 127 ("ms=%RU64\n", u64)); 128 128 129 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(& s_Cfg441StereoS16, 44100)) == RT_NS_1SEC, ("ns=%RU64\n", u64));130 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(& s_Cfg441StereoS16, 1)) == 22675, ("ns=%RU64\n", u64));131 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(& s_Cfg441StereoS16, 31)) == 702947, ("ns=%RU64\n", u64));132 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(& s_Cfg441StereoS16, 255)) == 5782312, ("ns=%RU64\n", u64));133 //RTTESTI_CHECK_MSG((u64 = DrvAudioHlpFramesToMicro(& s_Cfg441StereoS16, 44100)) == RT_US_1SEC,129 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(&Cfg441StereoS16, 44100)) == RT_NS_1SEC, ("ns=%RU64\n", u64)); 130 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(&Cfg441StereoS16, 1)) == 22675, ("ns=%RU64\n", u64)); 131 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(&Cfg441StereoS16, 31)) == 702947, ("ns=%RU64\n", u64)); 132 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToNano(&Cfg441StereoS16, 255)) == 5782312, ("ns=%RU64\n", u64)); 133 //RTTESTI_CHECK_MSG((u64 = DrvAudioHlpFramesToMicro(&Cfg441StereoS16, 44100)) == RT_US_1SEC, 134 134 // ("us=%RU64\n", u64)); 135 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToMilli(& s_Cfg441StereoS16, 44100)) == RT_MS_1SEC, ("ms=%RU64\n", u64));136 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToMilli(& s_Cfg441StereoS16, 255)) == 5, ("ms=%RU64\n", u64));137 138 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToFrames(& s_Cfg441StereoS16, RT_NS_1SEC)) == 44100, ("cb=%RU32\n", u32));139 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToFrames(& s_Cfg441StereoS16, 215876)) == 10, ("cb=%RU32\n", u32));140 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToFrames(& s_Cfg441StereoS16, RT_MS_1SEC)) == 44100, ("cb=%RU32\n", u32));141 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToFrames(& s_Cfg441StereoU32, 6)) == 265, ("cb=%RU32\n", u32));142 143 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToBytes(& s_Cfg441StereoS16, RT_NS_1SEC)) == 44100*2*2, ("cb=%RU32\n", u32));144 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToBytes(& s_Cfg441StereoS16, 702947)) == 31*2*2, ("cb=%RU32\n", u32));145 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToBytes(& s_Cfg441StereoS16, RT_MS_1SEC)) == 44100*2*2, ("cb=%RU32\n", u32));146 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToBytes(& s_Cfg441StereoS16, 5)) == 884, ("cb=%RU32\n", u32));135 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToMilli(&Cfg441StereoS16, 44100)) == RT_MS_1SEC, ("ms=%RU64\n", u64)); 136 RTTESTI_CHECK_MSG((u64 = PDMAudioPropsFramesToMilli(&Cfg441StereoS16, 255)) == 5, ("ms=%RU64\n", u64)); 137 138 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToFrames(&Cfg441StereoS16, RT_NS_1SEC)) == 44100, ("cb=%RU32\n", u32)); 139 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToFrames(&Cfg441StereoS16, 215876)) == 10, ("cb=%RU32\n", u32)); 140 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToFrames(&Cfg441StereoS16, RT_MS_1SEC)) == 44100, ("cb=%RU32\n", u32)); 141 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToFrames(&Cfg441StereoU32, 6)) == 265, ("cb=%RU32\n", u32)); 142 143 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToBytes(&Cfg441StereoS16, RT_NS_1SEC)) == 44100*2*2, ("cb=%RU32\n", u32)); 144 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsNanoToBytes(&Cfg441StereoS16, 702947)) == 31*2*2, ("cb=%RU32\n", u32)); 145 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToBytes(&Cfg441StereoS16, RT_MS_1SEC)) == 44100*2*2, ("cb=%RU32\n", u32)); 146 RTTESTI_CHECK_MSG((u32 = PDMAudioPropsMilliToBytes(&Cfg441StereoS16, 5)) == 884, ("cb=%RU32\n", u32)); 147 147 148 148 /* DrvAudioHlpClearBuf: */ … … 152 152 153 153 memset(pbPage, 0x42, PAGE_SIZE); 154 PDMAudioPropsClearBuffer(& s_Cfg441StereoS16, pbPage, PAGE_SIZE, PAGE_SIZE / 4);154 PDMAudioPropsClearBuffer(&Cfg441StereoS16, pbPage, PAGE_SIZE, PAGE_SIZE / 4); 155 155 RTTESTI_CHECK(ASMMemIsZero(pbPage, PAGE_SIZE)); 156 156 157 157 memset(pbPage, 0x42, PAGE_SIZE); 158 PDMAudioPropsClearBuffer(& s_Cfg441StereoU16, pbPage, PAGE_SIZE, PAGE_SIZE / 4);158 PDMAudioPropsClearBuffer(&Cfg441StereoU16, pbPage, PAGE_SIZE, PAGE_SIZE / 4); 159 159 for (uint32_t off = 0; off < PAGE_SIZE; off += 2) 160 160 RTTESTI_CHECK_MSG(pbPage[off] == 0x80 && pbPage[off + 1] == 0, ("off=%#x: %#x %x\n", off, pbPage[off], pbPage[off + 1])); 161 161 162 162 memset(pbPage, 0x42, PAGE_SIZE); 163 PDMAudioPropsClearBuffer(& s_Cfg441StereoU32, pbPage, PAGE_SIZE, PAGE_SIZE / 8);163 PDMAudioPropsClearBuffer(&Cfg441StereoU32, pbPage, PAGE_SIZE, PAGE_SIZE / 8); 164 164 for (uint32_t off = 0; off < PAGE_SIZE; off += 4) 165 165 RTTESTI_CHECK(pbPage[off] == 0x80 && pbPage[off + 1] == 0 && pbPage[off + 2] == 0 && pbPage[off + 3] == 0); … … 168 168 RTTestDisableAssertions(hTest); 169 169 memset(pbPage, 0x42, PAGE_SIZE); 170 PDMAudioPropsClearBuffer(& s_Cfg441StereoS16, pbPage, PAGE_SIZE, PAGE_SIZE); /* should adjust down the frame count. */170 PDMAudioPropsClearBuffer(&Cfg441StereoS16, pbPage, PAGE_SIZE, PAGE_SIZE); /* should adjust down the frame count. */ 171 171 RTTESTI_CHECK(ASMMemIsZero(pbPage, PAGE_SIZE)); 172 172 173 173 memset(pbPage, 0x42, PAGE_SIZE); 174 PDMAudioPropsClearBuffer(& s_Cfg441StereoU16, pbPage, PAGE_SIZE, PAGE_SIZE); /* should adjust down the frame count. */174 PDMAudioPropsClearBuffer(&Cfg441StereoU16, pbPage, PAGE_SIZE, PAGE_SIZE); /* should adjust down the frame count. */ 175 175 for (uint32_t off = 0; off < PAGE_SIZE; off += 2) 176 176 RTTESTI_CHECK_MSG(pbPage[off] == 0x80 && pbPage[off + 1] == 0, ("off=%#x: %#x %x\n", off, pbPage[off], pbPage[off + 1])); 177 177 178 178 memset(pbPage, 0x42, PAGE_SIZE); 179 PDMAudioPropsClearBuffer(& s_Cfg441StereoU32, pbPage, PAGE_SIZE, PAGE_SIZE); /* should adjust down the frame count. */179 PDMAudioPropsClearBuffer(&Cfg441StereoU32, pbPage, PAGE_SIZE, PAGE_SIZE); /* should adjust down the frame count. */ 180 180 for (uint32_t off = 0; off < PAGE_SIZE; off += 4) 181 181 RTTESTI_CHECK(pbPage[off] == 0x80 && pbPage[off + 1] == 0 && pbPage[off + 2] == 0 && pbPage[off + 3] == 0);
Note:
See TracChangeset
for help on using the changeset viewer.