VirtualBox

Changeset 107925 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jan 23, 2025 5:19:50 PM (4 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
167156
Message:

Audio: Added a new, optional config option 'CacheEnabled' (via global/per-VM 'VBoxInternal2/Audio/CacheEnabled') for audio drivers to disable caching code (if any). Currently only supported by DrvHostAudioWasApi, ignored everywhere else. bugref:10844

Location:
trunk/src/VBox/Devices/Audio
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r107735 r107925  
    47774777                                  "InputEnabled|"
    47784778                                  "OutputEnabled|"
     4779                                  "CacheEnabled|"
    47794780                                  "DebugEnabled|"
    47804781                                  "DebugPathOut|"
  • trunk/src/VBox/Devices/Audio/DrvHostAudioWasApi.cpp

    r107911 r107925  
    266266    RTCRITSECTRW                    CritSectStreamList;
    267267
     268    /** Whether the device cache (\a CacheHead and friends) is being used or not.
     269     *  Enabled by default, can be disabled via CFGM. */
     270    bool                            fCacheEnabled;
    268271    /** List of cached devices (DRVHOSTAUDIOWASCACHEDEV).
    269272     * Protected by CritSectCache  */
     
    850853static void drvHostAudioWasCachePrune(PDRVHOSTAUDIOWAS pThis)
    851854{
     855    AssertReturnVoid(pThis->fCacheEnabled);
     856
    852857    /*
    853858     * Prune each direction separately.
     
    898903static void drvHostAudioWasCachePurge(PDRVHOSTAUDIOWAS pThis, bool fOnWorker)
    899904{
     905    AssertReturnVoid(pThis->fCacheEnabled);
     906
    900907    for (;;)
    901908    {
     
    11171124 * If lookup fails, a new entry will be created.
    11181125 *
    1119  * @note    Called holding the lock, returning without holding it!
     1126 * @note    Called holding the cache's lock, returning without holding it!
    11201127 */
    11211128static int drvHostAudioWasCacheLookupOrCreateConfig(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASCACHEDEV pDevEntry,
     
    11231130                                                    PDRVHOSTAUDIOWASCACHEDEVCFG *ppDevCfg)
    11241131{
     1132    PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg;
     1133
    11251134    /*
    11261135     * Check if we've got a matching config.
    11271136     */
    1128     PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props);
    1129     if (pDevCfg)
    1130     {
    1131         *ppDevCfg = pDevCfg;
     1137    if (pThis->fCacheEnabled)
     1138    {
     1139        pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props);
     1140        if (pDevCfg)
     1141        {
     1142            *ppDevCfg = pDevCfg;
     1143            RTCritSectLeave(&pThis->CritSectCache);
     1144            Log8Func(("Config cache hit '%s' on '%ls': %p\n", pDevCfg->szProps, pDevEntry->wszDevId, pDevCfg));
     1145            return VINF_SUCCESS;
     1146        }
     1147
    11321148        RTCritSectLeave(&pThis->CritSectCache);
    1133         Log8Func(("Config cache hit '%s' on '%ls': %p\n", pDevCfg->szProps, pDevEntry->wszDevId, pDevCfg));
    1134         return VINF_SUCCESS;
    1135     }
    1136 
    1137     RTCritSectLeave(&pThis->CritSectCache);
     1149    }
    11381150
    11391151    /*
     
    11421154     */
    11431155    pDevCfg = (PDRVHOSTAUDIOWASCACHEDEVCFG)RTMemAllocZ(sizeof(*pDevCfg));
    1144     AssertReturn(pDevCfg, VERR_NO_MEMORY);
     1156    AssertPtrReturn(pDevCfg, VERR_NO_MEMORY);
    11451157    RTListInit(&pDevCfg->ListEntry);
    11461158    pDevCfg->pDevEntry         = pDevEntry;
     
    11521164    pDevCfg->nsLastUsed        = pDevCfg->nsCreated;
    11531165
    1154     uint32_t cCacheEntries;
    1155     if (pDevCfg->pDevEntry->enmDir == PDMAUDIODIR_IN)
    1156         cCacheEntries = ASMAtomicIncU32(&pThis->cCacheEntriesIn);
    1157     else
    1158         cCacheEntries = ASMAtomicIncU32(&pThis->cCacheEntriesOut);
    1159     if (cCacheEntries > VBOX_WASAPI_MAX_TOTAL_CONFIG_ENTRIES)
    1160     {
    1161         LogFlowFunc(("Trigger cache pruning.\n"));
    1162         int rc2 = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL /*pStream*/,
    1163                                                               DRVHOSTAUDIOWAS_DO_PRUNE_CACHE, NULL /*pvUser*/);
    1164         AssertRCStmt(rc2, drvHostAudioWasCachePrune(pThis));
     1166    if (pThis->fCacheEnabled)
     1167    {
     1168        uint32_t cCacheEntries;
     1169        if (pDevCfg->pDevEntry->enmDir == PDMAUDIODIR_IN)
     1170            cCacheEntries = ASMAtomicIncU32(&pThis->cCacheEntriesIn);
     1171        else
     1172            cCacheEntries = ASMAtomicIncU32(&pThis->cCacheEntriesOut);
     1173        if (cCacheEntries > VBOX_WASAPI_MAX_TOTAL_CONFIG_ENTRIES)
     1174        {
     1175            LogFlowFunc(("Trigger cache pruning.\n"));
     1176            int rc2 = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL /*pStream*/,
     1177                                                                  DRVHOSTAUDIOWAS_DO_PRUNE_CACHE, NULL /*pvUser*/);
     1178            AssertRCStmt(rc2, drvHostAudioWasCachePrune(pThis));
     1179        }
    11651180    }
    11661181
     
    12211236    if (SUCCEEDED(hrc))
    12221237    {
    1223         LogRel2(("WasAPI: Checking for cached device '%ls' ...\n", pwszDevId));
    1224 
    1225         size_t cwcDevId = RTUtf16Len(pwszDevId);
    1226 
    1227         /*
    1228          * The cache has two levels, so first the device entry.
    1229          */
    1230         PDRVHOSTAUDIOWASCACHEDEV pDevEntry, pDevEntryNext;
    1231         RTCritSectEnter(&pThis->CritSectCache);
    1232         RTListForEachSafe(&pThis->CacheHead, pDevEntry, pDevEntryNext, DRVHOSTAUDIOWASCACHEDEV, ListEntry)
    1233         {
    1234             if (   pDevEntry->cwcDevId == cwcDevId
    1235                 && pDevEntry->enmDir   == pCfgReq->enmDir
    1236                 && RTUtf16Cmp(pDevEntry->wszDevId, pwszDevId) == 0)
     1238        PDRVHOSTAUDIOWASCACHEDEV pDevEntry;
     1239        size_t                   cwcDevId = RTUtf16Len(pwszDevId);
     1240
     1241        if (pThis->fCacheEnabled)
     1242        {
     1243            LogRel2(("WasAPI: Checking for cached device '%ls' ...\n", pwszDevId));
     1244
     1245            /*
     1246             * The cache has two levels, so first the device entry.
     1247             */
     1248            PDRVHOSTAUDIOWASCACHEDEV pDevEntryNext;
     1249            RTCritSectEnter(&pThis->CritSectCache);
     1250            RTListForEachSafe(&pThis->CacheHead, pDevEntry, pDevEntryNext, DRVHOSTAUDIOWASCACHEDEV, ListEntry)
    12371251            {
    1238                 /*
    1239                  * Cache hit -- here we now need to also check if the device interface we want to look up
    1240                  * actually matches the one we have in the cache entry.
    1241                  *
    1242                  * If it doesn't, bail out and add a new device entry to the cache with the new interface below then.
    1243                  *
    1244                  * This is needed when switching audio interfaces and the device interface becomes invalid via
    1245                  * AUDCLNT_E_DEVICE_INVALIDATED.  See @bugref{10503}
    1246                  */
    1247                 if (pDevEntry->pIDevice != pIDevice)
     1252                if (   pDevEntry->cwcDevId == cwcDevId
     1253                    && pDevEntry->enmDir   == pCfgReq->enmDir
     1254                    && RTUtf16Cmp(pDevEntry->wszDevId, pwszDevId) == 0)
    12481255                {
    1249                     LogRel2(("WasAPI: Cache hit for device '%ls': Stale interface (new: %p, old: %p)\n",
    1250                               pDevEntry->wszDevId, pIDevice, pDevEntry->pIDevice));
    1251 
    1252                     LogRel(("WasAPI: Stale audio interface '%ls' detected!\n", pDevEntry->wszDevId));
    1253                     break;
     1256                    /*
     1257                     * Cache hit -- here we now need to also check if the device interface we want to look up
     1258                     * actually matches the one we have in the cache entry.
     1259                     *
     1260                     * If it doesn't, bail out and add a new device entry to the cache with the new interface below then.
     1261                     *
     1262                     * This is needed when switching audio interfaces and the device interface becomes invalid via
     1263                     * AUDCLNT_E_DEVICE_INVALIDATED.  See @bugref{10503}
     1264                     */
     1265                    if (pDevEntry->pIDevice != pIDevice)
     1266                    {
     1267                        LogRel2(("WasAPI: Cache hit for device '%ls': Stale interface (new: %p, old: %p)\n",
     1268                                  pDevEntry->wszDevId, pIDevice, pDevEntry->pIDevice));
     1269
     1270                        LogRel(("WasAPI: Stale audio interface '%ls' detected!\n", pDevEntry->wszDevId));
     1271                        break;
     1272                    }
     1273
     1274                    LogRel2(("WasAPI: Cache hit for device '%ls' (%p)\n", pwszDevId, pIDevice));
     1275
     1276                    CoTaskMemFree(pwszDevId);
     1277                    pwszDevId = NULL;
     1278
     1279                    return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg);
    12541280                }
    1255 
    1256                 LogRel2(("WasAPI: Cache hit for device '%ls' (%p)\n", pwszDevId, pIDevice));
    1257 
    1258                 CoTaskMemFree(pwszDevId);
    1259                 pwszDevId = NULL;
    1260 
    1261                 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg);
    12621281            }
    1263         }
    1264         RTCritSectLeave(&pThis->CritSectCache);
    1265 
    1266         LogRel2(("WasAPI: Cache miss for device '%ls' (%p)\n", pwszDevId, pIDevice));
     1282            RTCritSectLeave(&pThis->CritSectCache);
     1283
     1284            LogRel2(("WasAPI: Cache miss for device '%ls' (%p)\n", pwszDevId, pIDevice));
     1285        }
     1286        else
     1287            LogRel2(("WasAPI: Cache disabled for device '%ls' (%p)\n", pwszDevId, pIDevice));
    12671288
    12681289        /*
     
    12721293        if (pDevEntry)
    12731294        {
    1274             pIDevice->AddRef();
     1295            if (pThis->fCacheEnabled)
     1296                pIDevice->AddRef();
    12751297            pDevEntry->pIDevice                   = pIDevice;
    12761298            pDevEntry->enmDir                     = pCfgReq->enmDir;
     
    12871309            pwszDevId = NULL;
    12881310
    1289             /*
    1290              * Before adding the device, check that someone didn't race us adding it.
    1291              */
    1292             RTCritSectEnter(&pThis->CritSectCache);
    1293             PDRVHOSTAUDIOWASCACHEDEV pDevEntry2;
    1294             RTListForEach(&pThis->CacheHead, pDevEntry2, DRVHOSTAUDIOWASCACHEDEV, ListEntry)
     1311            if (pThis->fCacheEnabled)
    12951312            {
    1296                 if (   pDevEntry2->cwcDevId == cwcDevId
    1297                     /* Note: We have to compare the device interface here as well, as a cached device entry might
    1298                      * have a stale audio interface for the same device. In such a case a new device entry will be created below. */
    1299                     && pDevEntry2->pIDevice == pIDevice
    1300                     && pDevEntry2->enmDir   == pCfgReq->enmDir
    1301                     && RTUtf16Cmp(pDevEntry2->wszDevId, pDevEntry->wszDevId) == 0)
     1313                /*
     1314                 * Before adding the device to the cache, check that someone didn't race us adding it.
     1315                 */
     1316                RTCritSectEnter(&pThis->CritSectCache);
     1317                PDRVHOSTAUDIOWASCACHEDEV pDevEntry2;
     1318                RTListForEach(&pThis->CacheHead, pDevEntry2, DRVHOSTAUDIOWASCACHEDEV, ListEntry)
    13021319                {
    1303                     pIDevice->Release();
    1304                     RTMemFree(pDevEntry);
    1305                     pDevEntry = NULL;
    1306 
    1307                     LogRel2(("WasAPI: Lost race adding device '%ls': %p\n", pDevEntry2->wszDevId, pDevEntry2));
    1308                     return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry2, pCfgReq, fOnWorker, ppDevCfg);
     1320                    if (   pDevEntry2->cwcDevId == cwcDevId
     1321                        /* Note: We have to compare the device interface here as well, as a cached device entry might
     1322                         * have a stale audio interface for the same device. In such a case a new device entry will be created below. */
     1323                        && pDevEntry2->pIDevice == pIDevice
     1324                        && pDevEntry2->enmDir   == pCfgReq->enmDir
     1325                        && RTUtf16Cmp(pDevEntry2->wszDevId, pDevEntry->wszDevId) == 0)
     1326                    {
     1327                        pIDevice->Release();
     1328                        RTMemFree(pDevEntry);
     1329                        pDevEntry = NULL;
     1330
     1331                        LogRel2(("WasAPI: Lost race adding device '%ls': %p\n", pDevEntry2->wszDevId, pDevEntry2));
     1332                        return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry2, pCfgReq, fOnWorker, ppDevCfg);
     1333                    }
    13091334                }
     1335                RTListPrepend(&pThis->CacheHead, &pDevEntry->ListEntry);
     1336
     1337                LogRel2(("WasAPI: Added device '%ls' to cache: %p\n", pDevEntry->wszDevId, pDevEntry));
    13101338            }
    1311             RTListPrepend(&pThis->CacheHead, &pDevEntry->ListEntry);
    1312 
    1313             LogRel2(("WasAPI: Added device '%ls' to cache: %p\n", pDevEntry->wszDevId, pDevEntry));
     1339
    13141340            return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg);
    13151341        }
     
    13371363    if (SUCCEEDED(hrc))
    13381364    {
    1339         Log8Func(("Putting %p/'%s' back\n", pDevCfg, pDevCfg->szProps));
    1340         RTCritSectEnter(&pThis->CritSectCache);
    1341         RTListAppend(&pDevCfg->pDevEntry->ConfigList, &pDevCfg->ListEntry);
    1342         uint32_t const cEntries = pDevCfg->pDevEntry->enmDir == PDMAUDIODIR_IN ? pThis->cCacheEntriesIn : pThis->cCacheEntriesOut;
    1343         RTCritSectLeave(&pThis->CritSectCache);
    1344 
    1345         /* Trigger pruning if we're over the threshold. */
    1346         if (cEntries > VBOX_WASAPI_MAX_TOTAL_CONFIG_ENTRIES)
    1347         {
    1348             LogFlowFunc(("Trigger cache pruning.\n"));
    1349             int rc2 = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL /*pStream*/,
    1350                                                                   DRVHOSTAUDIOWAS_DO_PRUNE_CACHE, NULL /*pvUser*/);
    1351             AssertRCStmt(rc2, drvHostAudioWasCachePrune(pThis));
     1365        if (pThis->fCacheEnabled)
     1366        {
     1367            Log8Func(("Putting %p/'%s' back\n", pDevCfg, pDevCfg->szProps));
     1368            RTCritSectEnter(&pThis->CritSectCache);
     1369            RTListAppend(&pDevCfg->pDevEntry->ConfigList, &pDevCfg->ListEntry);
     1370            uint32_t const cEntries = pDevCfg->pDevEntry->enmDir == PDMAUDIODIR_IN ? pThis->cCacheEntriesIn : pThis->cCacheEntriesOut;
     1371            RTCritSectLeave(&pThis->CritSectCache);
     1372
     1373            /* Trigger pruning if we're over the threshold. */
     1374            if (cEntries > VBOX_WASAPI_MAX_TOTAL_CONFIG_ENTRIES)
     1375            {
     1376                LogFlowFunc(("Trigger cache pruning.\n"));
     1377                int rc2 = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL /*pStream*/,
     1378                                                                      DRVHOSTAUDIOWAS_DO_PRUNE_CACHE, NULL /*pvUser*/);
     1379                AssertRCStmt(rc2, drvHostAudioWasCachePrune(pThis));
     1380            }
    13521381        }
    13531382    }
     
    19151944            Assert(pStream == NULL);
    19161945            Assert(pvUser == NULL);
     1946            Assert(pThis->fCacheEnabled);
    19171947            drvHostAudioWasCachePurge(pThis, true /*fOnWorker*/);
    19181948            break;
     
    19211951            Assert(pStream == NULL);
    19221952            Assert(pvUser == NULL);
     1953            Assert(pThis->fCacheEnabled);
    19231954            drvHostAudioWasCachePrune(pThis);
    19241955            break;
     
    30303061    }
    30313062#else
    3032     if (!RTListIsEmpty(&pThis->CacheHead) && pThis->pIHostAudioPort)
     3063    if (   pThis->fCacheEnabled
     3064        && !RTListIsEmpty(&pThis->CacheHead) && pThis->pIHostAudioPort)
    30333065    {
    30343066        int rc = RTSemEventMultiCreate(&pThis->hEvtCachePurge);
     
    30923124#endif
    30933125
    3094     if (RTCritSectIsInitialized(&pThis->CritSectCache))
    3095     {
    3096         drvHostAudioWasCachePurge(pThis, false /*fOnWorker*/);
     3126    if (pThis->fCacheEnabled)
     3127    {
     3128        if (RTCritSectIsInitialized(&pThis->CritSectCache))
     3129        {
     3130            drvHostAudioWasCachePurge(pThis, false /*fOnWorker*/);
     3131            if (pThis->hEvtCachePurge != NIL_RTSEMEVENTMULTI)
     3132                RTSemEventMultiWait(pThis->hEvtCachePurge, RT_MS_30SEC);
     3133            RTCritSectDelete(&pThis->CritSectCache);
     3134        }
     3135
    30973136        if (pThis->hEvtCachePurge != NIL_RTSEMEVENTMULTI)
    3098             RTSemEventMultiWait(pThis->hEvtCachePurge, RT_MS_30SEC);
    3099         RTCritSectDelete(&pThis->CritSectCache);
    3100     }
    3101 
    3102     if (pThis->hEvtCachePurge != NIL_RTSEMEVENTMULTI)
    3103     {
    3104         RTSemEventMultiDestroy(pThis->hEvtCachePurge);
    3105         pThis->hEvtCachePurge = NIL_RTSEMEVENTMULTI;
     3137        {
     3138            RTSemEventMultiDestroy(pThis->hEvtCachePurge);
     3139            pThis->hEvtCachePurge = NIL_RTSEMEVENTMULTI;
     3140        }
     3141    }
     3142    else
     3143    {
     3144        Assert(pThis->cCacheEntriesIn == 0);
     3145        Assert(pThis->cCacheEntriesOut == 0);
    31063146    }
    31073147
     
    31813221     * Validate and read the configuration.
    31823222     */
    3183     PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "VmName|VmUuid|InputDeviceID|OutputDeviceID", "");
     3223    PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "VmName|VmUuid|InputDeviceID|OutputDeviceID|CacheEnabled", "");
    31843224
    31853225    char szTmp[1024];
     
    32003240    }
    32013241
     3242    /* Caching is enabled by default. */
     3243    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "CacheEnabled", &pThis->fCacheEnabled, true);
     3244    AssertMsgRCReturn(rc, ("Confguration error: Failed to read \"CacheEnabled\" as boolean: rc=%Rrc\n", rc), rc);
     3245
    32023246    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
    32033247                    ("Configuration error: Not possible to attach anything to this driver!\n"),
    32043248                    VERR_PDM_DRVINS_NO_ATTACH);
    32053249
     3250    LogRel2(("WasAPI: Caching device configuration entries is %s\n", pThis->fCacheEnabled ? "enabled" : "disabled"));
     3251
    32063252    /*
    32073253     * Initialize the critical sections early.
     
    32103256    AssertRCReturn(rc, rc);
    32113257
    3212     rc = RTCritSectInit(&pThis->CritSectCache);
    3213     AssertRCReturn(rc, rc);
     3258    if (pThis->fCacheEnabled)
     3259    {
     3260        rc = RTCritSectInit(&pThis->CritSectCache);
     3261        AssertRCReturn(rc, rc);
     3262    }
    32143263
    32153264    /*
     
    33223371     * Prime the cache.
    33233372     */
    3324     drvHostAudioWasCacheFill(pThis);
     3373    if (pThis->fCacheEnabled)
     3374        drvHostAudioWasCacheFill(pThis);
    33253375
    33263376    return VINF_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette