Changeset 89330 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- May 28, 2021 12:59:52 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144679
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
r89314 r89330 64 64 65 65 #ifdef DEBUG 66 DECLINLINE(void)audioMixBufDbgPrintInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc);67 DECL_FORCE_INLINE(bool)audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf);66 static void audioMixBufDbgPrintInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc); 67 static bool audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf); 68 68 #endif 69 69 … … 139 139 140 140 /** 141 * Returns a mutable pointer to the mixing buffer's audio frame buffer for writing raw142 * audio frames.143 *144 * @returns VBox status code. VINF_TRY_AGAIN for getting next pointer at beginning (circular).145 * @param pMixBuf Mixing buffer to acquire audio frames from.146 * @param cFrames Number of requested audio frames to write.147 * @param ppvFrames Returns a mutable pointer to the buffer's audio frame data.148 * @param pcFramesToWrite Number of available audio frames to write.149 *150 * @remark This function is not thread safe!151 */152 /** @todo r=bird: This isn't a 'ing Peek function, it's a Read function!153 * Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaarg!!!!!!!!!!!!!!!!!!! */154 int AudioMixBufPeekMutable(PAUDIOMIXBUF pMixBuf, uint32_t cFrames,155 PPDMAUDIOFRAME *ppvFrames, uint32_t *pcFramesToWrite)156 {157 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);158 AssertPtrReturn(ppvFrames, VERR_INVALID_POINTER);159 AssertPtrReturn(pcFramesToWrite, VERR_INVALID_POINTER);160 161 int rc;162 163 if (!cFrames)164 {165 *pcFramesToWrite = 0;166 return VINF_SUCCESS;167 }168 169 uint32_t cFramesToWrite;170 if (pMixBuf->offWrite + cFrames > pMixBuf->cFrames)171 {172 cFramesToWrite = pMixBuf->cFrames - pMixBuf->offWrite;173 rc = VINF_TRY_AGAIN;174 }175 else176 {177 cFramesToWrite = cFrames;178 rc = VINF_SUCCESS;179 }180 181 *ppvFrames = &pMixBuf->pFrames[pMixBuf->offWrite];182 AssertPtr(ppvFrames);183 184 pMixBuf->offWrite = (pMixBuf->offWrite + cFramesToWrite) % pMixBuf->cFrames;185 Assert(pMixBuf->offWrite <= pMixBuf->cFrames);186 pMixBuf->cUsed += RT_MIN(cFramesToWrite, pMixBuf->cUsed);187 188 *pcFramesToWrite = cFramesToWrite;189 190 return rc;191 }192 193 /**194 141 * Clears the entire frame buffer. 195 142 * … … 219 166 220 167 AssertStmt(cFramesToClear <= pMixBuf->cFrames, cFramesToClear = pMixBuf->cFrames); 221 222 /** @todo r=bird: Why isn't this done when reading/releaseing ? */223 PAUDIOMIXBUF pIter;224 RTListForEach(&pMixBuf->lstChildren, pIter, AUDIOMIXBUF, Node)225 {226 AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",227 pIter->pszName, pIter->cMixed, pIter->cMixed - cFramesToClear));228 229 pIter->cMixed -= RT_MIN(pIter->cMixed, cFramesToClear);230 /* Note: Do not increment pIter->cUsed here, as this gets done when reading from that buffer using AudioMixBufReadXXX. */231 }232 168 233 169 /** @todo r=bird: waste of time? */ … … 290 226 pMixBuf->uMagic = ~AUDIOMIXBUF_MAGIC; 291 227 292 AudioMixBufUnlink(pMixBuf);293 294 228 if (pMixBuf->pszName) 295 229 { … … 327 261 AssertPtrReturn(pMixBuf, 0); 328 262 329 uint32_t cFrames, cFramesFree; 330 if (pMixBuf->pParent) 331 { 332 /* 333 * As a linked child buffer we want to know how many frames 334 * already have been consumed by the parent. 335 */ 336 cFrames = pMixBuf->pParent->cFrames; 337 338 Assert(pMixBuf->cMixed <= cFrames); 339 cFramesFree = cFrames - pMixBuf->cMixed; 340 } 341 else /* As a parent. */ 342 { 343 cFrames = pMixBuf->cFrames; 344 Assert(cFrames >= pMixBuf->cUsed); 345 cFramesFree = pMixBuf->cFrames - pMixBuf->cUsed; 346 } 263 uint32_t const cFrames = pMixBuf->cFrames; 264 uint32_t cUsed = pMixBuf->cUsed; 265 AssertStmt(cUsed <= cFrames, cUsed = cFrames); 266 uint32_t const cFramesFree = cFrames - cUsed; 347 267 348 268 AUDMIXBUF_LOG(("%s: %RU32 of %RU32\n", pMixBuf->pszName, cFramesFree, cFrames)); … … 1239 1159 1240 1160 pMixBuf->uMagic = AUDIOMIXBUF_MAGIC; 1241 pMixBuf->pParent = NULL;1242 1243 RTListInit(&pMixBuf->lstChildren);1244 pMixBuf->cChildren = 0;1245 1161 1246 1162 pMixBuf->pFrames = NULL; … … 1288 1204 1289 1205 /** 1290 * Returns @c true if there are any audio frames available for processing,1291 * @c false if not.1292 * 1293 * @ret urn bool @c true if there are any audio frames available for processing, @c false if not.1294 * @param pMixBuf Mixing buffer to return value for.1295 */ 1296 bool AudioMixBufIsEmpty(P AUDIOMIXBUF pMixBuf)1206 * Checks if the buffer is empty. 1207 * 1208 * @retval true if empty buffer. 1209 * @retval false if not empty and there are frames to be processed. 1210 * @param pMixBuf The mixing buffer. 1211 */ 1212 bool AudioMixBufIsEmpty(PCAUDIOMIXBUF pMixBuf) 1297 1213 { 1298 1214 AssertPtrReturn(pMixBuf, true); 1299 1300 if (pMixBuf->pParent) 1301 return (pMixBuf->cMixed == 0); 1302 return (pMixBuf->cUsed == 0); 1303 } 1304 1305 /** 1306 * Calculates the frequency (sample rate) ratio of mixing buffer A in relation to mixing buffer B. 1307 * 1308 * @returns Calculated frequency ratio. 1309 * @param pMixBufA First mixing buffer. 1310 * @param pMixBufB Second mixing buffer. 1311 */ 1312 static int64_t audioMixBufCalcFreqRatio(PAUDIOMIXBUF pMixBufA, PAUDIOMIXBUF pMixBufB) 1313 { 1314 int64_t iRatio = (int64_t)((uint64_t)PDMAudioPropsHz(&pMixBufA->Props) << 32) / PDMAudioPropsHz(&pMixBufB->Props); 1315 AssertStmt(iRatio, iRatio = RT_BIT_64(32) /*1:1*/); 1316 return iRatio; 1317 } 1318 1319 /** 1320 * Links an audio mixing buffer to a parent mixing buffer. 1321 * 1322 * A parent mixing buffer can have multiple children mixing buffers [1:N], 1323 * whereas a child only can have one parent mixing buffer [N:1]. 1324 * 1325 * The mixing direction always goes from the child/children buffer(s) to the 1326 * parent buffer. 1327 * 1328 * For guest audio output the host backend "owns" the parent mixing buffer, the 1329 * device emulation "owns" the child/children. 1330 * 1331 * The audio format of each mixing buffer can vary; the internal mixing code 1332 * then will automatically do the (needed) conversion. 1333 * 1334 * @returns VBox status code. 1335 * @param pMixBuf Mixing buffer to link parent to. 1336 * @param pParent Parent mixing buffer to use for linking. 1337 * 1338 * @remark Circular linking is not allowed. 1339 */ 1340 int AudioMixBufLinkTo(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUF pParent) 1341 { 1342 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER); 1343 AssertPtrReturn(pParent, VERR_INVALID_POINTER); 1344 1345 AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->uAudioFmt), 1346 ("Parent frame frequency (Hz) not set\n"), VERR_INVALID_PARAMETER); 1347 AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt), 1348 ("Buffer sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER); 1349 AssertMsgReturn(pMixBuf != pParent, 1350 ("Circular linking not allowed\n"), VERR_INVALID_PARAMETER); 1351 1352 if (pMixBuf->pParent) /* Already linked? */ 1353 { 1354 AUDMIXBUF_LOG(("%s: Already linked to parent '%s'\n", 1355 pMixBuf->pszName, pMixBuf->pParent->pszName)); 1356 return VERR_ACCESS_DENIED; 1357 } 1358 1359 RTListAppend(&pParent->lstChildren, &pMixBuf->Node); 1360 pParent->cChildren++; 1361 1362 /* Set the parent. */ 1363 pMixBuf->pParent = pParent; 1364 1365 /* Calculate the frequency ratios. */ 1366 pMixBuf->iFreqRatio = audioMixBufCalcFreqRatio(pParent, pMixBuf); 1367 1368 int rc = VINF_SUCCESS; 1369 #if 0 1370 uint32_t cFrames = (uint32_t)RT_MIN( ((uint64_t)pParent->cFrames << 32) 1371 / pMixBuf->iFreqRatio, _64K /* 64K frames max. */); 1372 if (!cFrames) 1373 cFrames = pParent->cFrames; 1374 1375 int rc = VINF_SUCCESS; 1376 1377 if (cFrames != pMixBuf->cFrames) 1378 { 1379 AUDMIXBUF_LOG(("%s: Reallocating frames %RU32 -> %RU32\n", 1380 pMixBuf->pszName, pMixBuf->cFrames, cFrames)); 1381 1382 uint32_t cbSamples = cFrames * sizeof(PDMAUDIOSAMPLE); 1383 Assert(cbSamples); 1384 pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemRealloc(pMixBuf->pSamples, cbSamples); 1385 if (!pMixBuf->pSamples) 1386 rc = VERR_NO_MEMORY; 1387 1388 if (RT_SUCCESS(rc)) 1389 { 1390 pMixBuf->cFrames = cFrames; 1391 1392 /* Make sure to zero the reallocated buffer so that it can be 1393 * used properly when blending with another buffer later. */ 1394 RT_BZERO(pMixBuf->pSamples, cbSamples); 1395 } 1396 } 1397 #endif 1398 1399 if (RT_SUCCESS(rc)) 1400 { 1401 if (!pMixBuf->pRate) 1402 { 1403 pMixBuf->pRate = (PAUDIOSTREAMRATE)RTMemAllocZ(sizeof(AUDIOSTREAMRATE)); 1404 AssertReturn(pMixBuf->pRate, VERR_NO_MEMORY); 1405 } 1406 else 1407 RT_BZERO(pMixBuf->pRate, sizeof(AUDIOSTREAMRATE)); 1408 1409 /* 1410 * Some examples to get an idea of what uDstInc holds: 1411 * 44100 to 44100 -> (44100<<32) / 44100 = 0x01'00000000 (4294967296) 1412 * 22050 to 44100 -> (22050<<32) / 44100 = 0x00'80000000 (2147483648) 1413 * 44100 to 22050 -> (44100<<32) / 22050 = 0x02'00000000 (8589934592) 1414 * 44100 to 48000 -> (44100<<32) / 48000 = 0x00'EB333333 (3946001203.2) 1415 * 48000 to 44100 -> (48000<<32) / 44100 = 0x01'16A3B35F (4674794335.7823129251700680272109) 1416 * 1417 * Note! The iFreqRatio is the same but with the frequencies switched. 1418 */ 1419 pMixBuf->pRate->uDstInc = ((uint64_t)PDMAudioPropsHz(&pMixBuf->Props) << 32) / PDMAudioPropsHz(&pParent->Props); 1420 1421 AUDMIXBUF_LOG(("%RU32 Hz vs parent %RU32 Hz => iFreqRatio=0x%'RX64 uDstInc=0x%'RX64; cFrames=%RU32 (%RU32 parent); name: %s, parent: %s\n", 1422 PDMAudioPropsHz(&pMixBuf->Props), PDMAudioPropsHz(&pParent->Props), pMixBuf->iFreqRatio, 1423 pMixBuf->pRate->uDstInc, pMixBuf->cFrames, pParent->cFrames, pMixBuf->pszName, pMixBuf->pParent->pszName)); 1424 } 1425 1426 return rc; 1215 return pMixBuf->cUsed == 0; 1427 1216 } 1428 1217 … … 1444 1233 AssertPtrReturn(pMixBuf, 0); 1445 1234 1446 #ifdef RT_STRICT 1447 uint32_t cFrames; 1448 #endif 1449 uint32_t cAvail; 1450 if (pMixBuf->pParent) /* Is this a child buffer? */ 1451 { 1452 #ifdef RT_STRICT 1453 /* Use the frame count from the parent, as 1454 * pMixBuf->cMixed specifies the frame count 1455 * in parent frames. */ 1456 cFrames = pMixBuf->pParent->cFrames; 1457 #endif 1458 cAvail = pMixBuf->cMixed; 1459 } 1460 else 1461 { 1462 #ifdef RT_STRICT 1463 cFrames = pMixBuf->cFrames; 1464 #endif 1465 cAvail = pMixBuf->cUsed; 1466 } 1467 1468 Assert(cAvail <= cFrames); 1235 uint32_t const cFrames = pMixBuf->cFrames; 1236 uint32_t cAvail = pMixBuf->cUsed; 1237 AssertStmt(cAvail <= cFrames, cAvail = cFrames); 1469 1238 return cAvail; 1470 }1471 1472 /**1473 * Mixes audio frames from a source mixing buffer to a destination mixing buffer.1474 *1475 * @returns VBox status code.1476 * VERR_BUFFER_UNDERFLOW if the source did not have enough audio data.1477 * VERR_BUFFER_OVERFLOW if the destination did not have enough space to store the converted source audio data.1478 *1479 * @param pDst Destination mixing buffer.1480 * @param pSrc Source mixing buffer.1481 * @param cSrcOff Offset of source audio frames to mix.1482 * @param cSrcFrames Number of source audio frames to mix.1483 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.1484 */1485 static int audioMixBufMixTo(PAUDIOMIXBUF pDst, PAUDIOMIXBUF pSrc, uint32_t cSrcOff, uint32_t cSrcFrames,1486 uint32_t *pcSrcMixed)1487 {1488 AssertPtrReturn(pDst, VERR_INVALID_POINTER);1489 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);1490 /* pcSrcMixed is optional. */1491 1492 AssertMsgReturn(pDst == pSrc->pParent, ("Source buffer '%s' is not a child of destination '%s'\n",1493 pSrc->pszName, pDst->pszName), VERR_INVALID_PARAMETER);1494 uint32_t cReadTotal = 0;1495 uint32_t cWrittenTotal = 0;1496 1497 Assert(pSrc->cMixed <= pDst->cFrames);1498 1499 Assert(pSrc->cUsed >= pDst->cMixed);1500 Assert(pDst->cUsed <= pDst->cFrames);1501 1502 uint32_t offSrcRead = cSrcOff;1503 1504 uint32_t offDstWrite = pDst->offWrite;1505 uint32_t cDstMixed = pSrc->cMixed;1506 1507 uint32_t cSrcAvail = RT_MIN(cSrcFrames, pSrc->cUsed);1508 uint32_t cDstAvail = pDst->cFrames - pDst->cUsed; /** @todo Use pDst->cMixed later? */1509 1510 AUDMIXBUF_LOG(("%s (%RU32 available) -> %s (%RU32 available)\n",1511 pSrc->pszName, cSrcAvail, pDst->pszName, cDstAvail));1512 #ifdef DEBUG1513 audioMixBufDbgPrintInternal(pDst, __FUNCTION__);1514 #endif1515 1516 if (!cSrcAvail)1517 return VERR_BUFFER_UNDERFLOW;1518 1519 if (!cDstAvail)1520 return VERR_BUFFER_OVERFLOW;1521 1522 uint32_t cSrcToRead = 0;1523 uint32_t cSrcRead;1524 1525 uint32_t cDstToWrite;1526 uint32_t cDstWritten;1527 1528 int rc = VINF_SUCCESS;1529 1530 while (cSrcAvail && cDstAvail)1531 {1532 cSrcToRead = RT_MIN(cSrcAvail, pSrc->cFrames - offSrcRead);1533 cDstToWrite = RT_MIN(cDstAvail, pDst->cFrames - offDstWrite);1534 1535 AUDMIXBUF_LOG((" Src: %RU32 @ %RU32 -> reading %RU32\n", cSrcAvail, offSrcRead, cSrcToRead));1536 AUDMIXBUF_LOG((" Dst: %RU32 @ %RU32 -> writing %RU32\n", cDstAvail, offDstWrite, cDstToWrite));1537 1538 if ( !cDstToWrite1539 || !cSrcToRead)1540 {1541 break;1542 }1543 1544 cDstWritten = cSrcRead = 0;1545 1546 Assert(offSrcRead < pSrc->cFrames);1547 Assert(offSrcRead + cSrcToRead <= pSrc->cFrames);1548 1549 Assert(offDstWrite < pDst->cFrames);1550 Assert(offDstWrite + cDstToWrite <= pDst->cFrames);1551 1552 audioMixBufOpAssign(pDst->pFrames + offDstWrite, cDstToWrite,1553 pSrc->pFrames + offSrcRead, cSrcToRead,1554 pSrc->pRate, &cDstWritten, &cSrcRead);1555 1556 cReadTotal += cSrcRead;1557 cWrittenTotal += cDstWritten;1558 1559 offSrcRead = (offSrcRead + cSrcRead) % pSrc->cFrames;1560 offDstWrite = (offDstWrite + cDstWritten) % pDst->cFrames;1561 1562 cDstMixed += cDstWritten;1563 1564 Assert(cSrcAvail >= cSrcRead);1565 cSrcAvail -= cSrcRead;1566 1567 Assert(cDstAvail >= cDstWritten);1568 cDstAvail -= cDstWritten;1569 1570 AUDMIXBUF_LOG((" %RU32 read (%RU32 left @ %RU32), %RU32 written (%RU32 left @ %RU32)\n",1571 cSrcRead, cSrcAvail, offSrcRead,1572 cDstWritten, cDstAvail, offDstWrite));1573 }1574 1575 pSrc->offRead = offSrcRead;1576 Assert(pSrc->cUsed >= cReadTotal);1577 pSrc->cUsed -= RT_MIN(pSrc->cUsed, cReadTotal);1578 1579 /* Note: Always count in parent frames, as the rate can differ! */1580 pSrc->cMixed = RT_MIN(cDstMixed, pDst->cFrames);1581 1582 pDst->offWrite = offDstWrite;1583 Assert(pDst->offWrite <= pDst->cFrames);1584 Assert((pDst->cUsed + cWrittenTotal) <= pDst->cFrames);1585 pDst->cUsed += cWrittenTotal;1586 1587 /* If there are more used frames than fitting in the destination buffer,1588 * adjust the values accordingly.1589 *1590 * This can happen if this routine has been called too often without1591 * actually processing the destination buffer in between. */1592 if (pDst->cUsed > pDst->cFrames)1593 {1594 LogFunc(("%s: Warning: Destination buffer used %RU32 / %RU32 frames\n", pDst->pszName, pDst->cUsed, pDst->cFrames));1595 pDst->offWrite = 0;1596 pDst->cUsed = pDst->cFrames;1597 1598 rc = VERR_BUFFER_OVERFLOW;1599 }1600 1601 #ifdef DEBUG1602 audioMixBufDbgValidate(pSrc);1603 audioMixBufDbgValidate(pDst);1604 1605 Assert(pSrc->cMixed <= pDst->cFrames);1606 #endif1607 1608 #ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA1609 uint32_t offRead = pDst->offRead;1610 1611 uint32_t cLeft = cWrittenTotal;1612 while (cLeft)1613 {1614 uint8_t auBuf[256];1615 RT_ZERO(auBuf);1616 1617 Assert(sizeof(auBuf) >= 4);1618 Assert(sizeof(auBuf) % 4 == 0);1619 1620 uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2F(pDst, sizeof(auBuf)), RT_MIN(cLeft, pDst->cFrames - offRead));1621 Assert(cToRead <= pDst->cUsed);1622 1623 AUDMIXBUFCONVOPTS convOpts;1624 RT_ZERO(convOpts);1625 convOpts.cFrames = cToRead;1626 1627 pDst->pfnConvTo(auBuf, pDst->pFrames + offRead, &convOpts);1628 1629 RTFILE fh;1630 int rc2 = RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_mixto.pcm",1631 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);1632 if (RT_SUCCESS(rc2))1633 {1634 RTFileWrite(fh, auBuf, AUDIOMIXBUF_F2B(pDst, cToRead), NULL);1635 RTFileClose(fh);1636 }1637 1638 offRead = (offRead + cToRead) % pDst->cFrames;1639 cLeft -= cToRead;1640 }1641 #endif /* AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA */1642 1643 #ifdef DEBUG1644 audioMixBufDbgPrintInternal(pDst, __FUNCTION__);1645 #endif1646 1647 if (pcSrcMixed)1648 *pcSrcMixed = cReadTotal;1649 1650 AUDMIXBUF_LOG(("cReadTotal=%RU32, cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstUsed=%RU32, rc=%Rrc\n",1651 cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cUsed, rc));1652 return rc;1653 }1654 1655 /**1656 * Mixes audio frames down to the parent mixing buffer, extended version.1657 *1658 * @returns VBox status code. See audioMixBufMixTo() for a more detailed explanation.1659 * @param pMixBuf Source mixing buffer to mix to its parent.1660 * @param cSrcOffset Offset (in frames) of source mixing buffer.1661 * @param cSrcFrames Number of source audio frames to mix to its parent.1662 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.1663 */1664 int AudioMixBufMixToParentEx(PAUDIOMIXBUF pMixBuf, uint32_t cSrcOffset, uint32_t cSrcFrames, uint32_t *pcSrcMixed)1665 {1666 AssertMsgReturn(VALID_PTR(pMixBuf->pParent),1667 ("Buffer is not linked to a parent buffer\n"),1668 VERR_INVALID_PARAMETER);1669 1670 return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, cSrcOffset, cSrcFrames, pcSrcMixed);1671 }1672 1673 /**1674 * Mixes audio frames down to the parent mixing buffer.1675 *1676 * @returns VBox status code. See audioMixBufMixTo() for a more detailed explanation.1677 * @param pMixBuf Source mixing buffer to mix to its parent.1678 * @param cSrcFrames Number of source audio frames to mix to its parent.1679 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.1680 */1681 int AudioMixBufMixToParent(PAUDIOMIXBUF pMixBuf, uint32_t cSrcFrames, uint32_t *pcSrcMixed)1682 {1683 return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, pMixBuf->offRead, cSrcFrames, pcSrcMixed);1684 1239 } 1685 1240 … … 1693 1248 * @param pMixBuf Mixing buffer to print. 1694 1249 * @param pszFunc Function name to log this for. 1695 * @param fIsParent Whether this is a parent buffer or not.1696 1250 * @param uIdtLvl Indention level to use. 1697 1251 */ 1698 DECL_FORCE_INLINE(void) audioMixBufDbgPrintSingle(PAUDIOMIXBUF pMixBuf, const char *pszFunc, bool fIsParent, uint16_t uIdtLvl)1699 { 1700 Log(("%s: %*s [%s]%s: offRead=%RU32, offWrite=%RU32, cMixed=%RU32 -> %RU32/%RU32\n",1701 pszFunc, uIdtLvl * 4, "", fIsParent ? "PARENT" : "CHILD",1252 static void audioMixBufDbgPrintSingle(PAUDIOMIXBUF pMixBuf, const char *pszFunc, uint16_t uIdtLvl) 1253 { 1254 Log(("%s: %*s %s: offRead=%RU32, offWrite=%RU32, cMixed=%RU32 -> %RU32/%RU32\n", 1255 pszFunc, uIdtLvl * 4, "", 1702 1256 pMixBuf->pszName, pMixBuf->offRead, pMixBuf->offWrite, pMixBuf->cMixed, pMixBuf->cUsed, pMixBuf->cFrames)); 1703 1257 } … … 1709 1263 * @param pMixBuf Mixing buffer to validate. 1710 1264 */ 1711 DECL_FORCE_INLINE(bool)audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf)1265 static bool audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf) 1712 1266 { 1713 1267 //const uint32_t offReadEnd = (pMixBuf->offRead + pMixBuf->cUsed) % pMixBuf->cFrames; … … 1741 1295 1742 1296 /** 1743 * Internal helper function for audioMixBufPrintChain().1744 * Do not use directly.1745 *1746 * @returns VBox status code.1747 * @param pMixBuf Mixing buffer to print.1748 * @param pszFunc Function name to print the chain for.1749 * @param uIdtLvl Indention level to use.1750 * @param pcChildren Pointer to children counter.1751 */1752 DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainHelper(PAUDIOMIXBUF pMixBuf, const char *pszFunc, uint16_t uIdtLvl,1753 size_t *pcChildren)1754 {1755 PAUDIOMIXBUF pIter;1756 RTListForEach(&pMixBuf->lstChildren, pIter, AUDIOMIXBUF, Node)1757 {1758 audioMixBufDbgPrintSingle(pIter, pszFunc, false /* ifIsParent */, uIdtLvl + 1);1759 *pcChildren++;1760 }1761 }1762 1763 DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc)1764 {1765 PAUDIOMIXBUF pParent = pMixBuf->pParent;1766 while (pParent)1767 {1768 if (!pParent->pParent)1769 break;1770 1771 pParent = pParent->pParent;1772 }1773 1774 if (!pParent)1775 pParent = pMixBuf;1776 1777 audioMixBufDbgPrintSingle(pParent, pszFunc, true /* fIsParent */, 0 /* uIdtLvl */);1778 1779 /* Recursively iterate children. */1780 size_t cChildren = 0;1781 audioMixBufDbgPrintChainHelper(pParent, pszFunc, 0 /* uIdtLvl */, &cChildren);1782 1783 Log(("%s: Children: %zu\n", pszFunc, cChildren));1784 }1785 1786 /**1787 1297 * Prints statistics and status of the full chain of a mixing buffer to the logger, 1788 1298 * starting from the top root mixing buffer. … … 1794 1304 void AudioMixBufDbgPrintChain(PAUDIOMIXBUF pMixBuf) 1795 1305 { 1796 audioMixBufDbgPrint ChainInternal(pMixBuf, __FUNCTION__);1306 audioMixBufDbgPrintSingle(pMixBuf, __FUNCTION__, 0 /* uIdtLvl */); 1797 1307 } 1798 1308 1799 1309 DECL_FORCE_INLINE(void) audioMixBufDbgPrintInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc) 1800 1310 { 1801 PAUDIOMIXBUF pParent = pMixBuf; 1802 if (pMixBuf->pParent) 1803 pParent = pMixBuf->pParent; 1804 1805 audioMixBufDbgPrintSingle(pMixBuf, pszFunc, pParent == pMixBuf /* fIsParent */, 0 /* iIdtLevel */); 1806 1807 PAUDIOMIXBUF pIter; 1808 RTListForEach(&pMixBuf->lstChildren, pIter, AUDIOMIXBUF, Node) 1809 { 1810 if (pIter == pMixBuf) 1811 continue; 1812 audioMixBufDbgPrintSingle(pIter, pszFunc, false /* fIsParent */, 1 /* iIdtLevel */); 1813 } 1311 audioMixBufDbgPrintSingle(pMixBuf, pszFunc, 0 /* iIdtLevel */); 1814 1312 } 1815 1313 … … 2970 2468 2971 2469 /** 2972 * Unlinks a mixing buffer from its parent, if any.2973 *2974 * @returns VBox status code.2975 * @param pMixBuf Mixing buffer to unlink from parent.2976 */2977 void AudioMixBufUnlink(PAUDIOMIXBUF pMixBuf)2978 {2979 if (!pMixBuf || !pMixBuf->pszName)2980 return;2981 2982 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));2983 2984 if (pMixBuf->pParent) /* IS this a children buffer? */2985 {2986 AUDMIXBUF_LOG(("%s: Unlinking from parent \"%s\"\n",2987 pMixBuf->pszName, pMixBuf->pParent->pszName));2988 2989 RTListNodeRemove(&pMixBuf->Node);2990 2991 /* Decrease the paren't children count. */2992 Assert(pMixBuf->pParent->cChildren);2993 pMixBuf->pParent->cChildren--;2994 2995 /* Make sure to reset the parent mixing buffer each time it gets linked2996 * to a new child. */2997 AudioMixBufReset(pMixBuf->pParent);2998 pMixBuf->pParent = NULL;2999 }3000 3001 PAUDIOMIXBUF pChild, pChildNext;3002 RTListForEachSafe(&pMixBuf->lstChildren, pChild, pChildNext, AUDIOMIXBUF, Node)3003 {3004 AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pChild->pszName));3005 3006 AudioMixBufReset(pChild);3007 3008 Assert(pChild->pParent == pMixBuf);3009 pChild->pParent = NULL;3010 3011 RTListNodeRemove(&pChild->Node);3012 3013 /* Decrease the children count. */3014 Assert(pMixBuf->cChildren);3015 pMixBuf->cChildren--;3016 }3017 3018 Assert(RTListIsEmpty(&pMixBuf->lstChildren));3019 Assert(pMixBuf->cChildren == 0);3020 3021 AudioMixBufReset(pMixBuf);3022 3023 if (pMixBuf->pRate)3024 {3025 pMixBuf->pRate->offDst = pMixBuf->pRate->offSrc = 0;3026 pMixBuf->pRate->uDstInc = 0;3027 }3028 3029 pMixBuf->iFreqRatio = 1; /* Prevent division by zero. */3030 }3031 3032 /**3033 2470 * Writes audio frames at a specific offset. 3034 2471 * The sample format being written must match the format of the mixing buffer. -
trunk/src/VBox/Devices/Audio/AudioMixBuffer.h
r89314 r89330 220 220 * @note This also is known as the distance in ring buffer terms. */ 221 221 uint32_t cUsed; 222 /** Number of children mix buffers kept in lstChildren. */223 uint32_t cChildren;224 /** List of children mix buffers to keep in sync with (if being a parent buffer). */225 RTLISTANCHOR lstChildren;226 /** Pointer to parent buffer (if any). */227 PAUDIOMIXBUF pParent;228 222 /** Intermediate structure for buffer conversion tasks. */ 229 223 PAUDIOSTREAMRATE pRate; … … 315 309 uint32_t AudioMixBufFree(PAUDIOMIXBUF pMixBuf); 316 310 uint32_t AudioMixBufFreeBytes(PAUDIOMIXBUF pMixBuf); 317 bool AudioMixBufIsEmpty(PAUDIOMIXBUF pMixBuf); 318 int AudioMixBufLinkTo(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUF pParent); 311 bool AudioMixBufIsEmpty(PCAUDIOMIXBUF pMixBuf); 319 312 uint32_t AudioMixBufLive(PAUDIOMIXBUF pMixBuf); 320 int AudioMixBufMixToParent(PAUDIOMIXBUF pMixBuf, uint32_t cSrcFrames, uint32_t *pcSrcMixed);321 int AudioMixBufMixToParentEx(PAUDIOMIXBUF pMixBuf, uint32_t cSrcOffset, uint32_t cSrcFrames, uint32_t *pcSrcMixed);322 int AudioMixBufPeekMutable(PAUDIOMIXBUF pMixBuf, uint32_t cFramesToRead, PPDMAUDIOFRAME *ppvSamples, uint32_t *pcFramesRead);323 313 uint32_t AudioMixBufUsed(PAUDIOMIXBUF pMixBuf); 324 314 uint32_t AudioMixBufUsedBytes(PAUDIOMIXBUF pMixBuf); … … 332 322 uint32_t AudioMixBufSize(PAUDIOMIXBUF pMixBuf); 333 323 uint32_t AudioMixBufSizeBytes(PAUDIOMIXBUF pMixBuf); 334 void AudioMixBufUnlink(PAUDIOMIXBUF pMixBuf);335 324 int AudioMixBufWriteAt(PAUDIOMIXBUF pMixBuf, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten); 336 325 int AudioMixBufWriteAtEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pSrcProps, uint32_t offFrames, -
trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
r88923 r89330 307 307 } 308 308 309 #if 0 /* obsolete */ 309 310 static int tstParentChild(RTTEST hTest) 310 311 { … … 447 448 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS; 448 449 } 449 450 450 #endif 451 452 453 #if 0 /** @todo rewrite to non-parent/child setup */ 451 454 static void tstDownsampling(RTTEST hTest, uint32_t uFromHz, uint32_t uToHz) 452 455 { … … 547 550 AudioMixBufDestroy(&Child); 548 551 } 552 #endif 549 553 550 554 … … 654 658 655 659 660 #if 0 /** @todo rewrite to non-parent/child setup */ 656 661 /* Test 8-bit sample conversion (8-bit -> internal -> 8-bit). */ 657 662 static int tstConversion8(RTTEST hTest) … … 756 761 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS; 757 762 } 758 763 #endif 764 765 #if 0 /** @todo rewrite to non-parent/child setup */ 759 766 /* Test 16-bit sample conversion (16-bit -> internal -> 16-bit). */ 760 767 static int tstConversion16(RTTEST hTest) … … 849 856 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS; 850 857 } 851 858 #endif 859 860 #if 0 /** @todo rewrite to non-parent/child setup */ 852 861 /* Test volume control. */ 853 862 static int tstVolume(RTTEST hTest) … … 965 974 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS; 966 975 } 976 #endif 967 977 968 978 int main(int argc, char **argv) … … 981 991 tstBasics(hTest); 982 992 tstSingle(hTest); 983 tstParentChild(hTest); 984 tstConversion8(hTest); 985 tstConversion16(hTest); 986 tstVolume(hTest); 993 //tstParentChild(hTest); 994 //tstConversion8(hTest); 995 //tstConversion16(hTest); 996 //tstVolume(hTest); 997 #if 0 /** @todo rewrite to non-parent/child setup */ 987 998 tstDownsampling(hTest, 44100, 22050); 988 999 tstDownsampling(hTest, 48000, 44100); 989 1000 tstDownsampling(hTest, 48000, 22050); 990 1001 tstDownsampling(hTest, 48000, 11000); 1002 #endif 991 1003 tstNewPeek(hTest, 48000, 48000); 992 1004 tstNewPeek(hTest, 48000, 11000);
Note:
See TracChangeset
for help on using the changeset viewer.