VirtualBox

Changeset 87942 in vbox


Ignore:
Timestamp:
Mar 3, 2021 5:26:37 PM (4 years ago)
Author:
vboxsync
Message:

Audio/HDA: Follow-up fix for r142810 to make the transfer heuristics also work for surround speaker setups. ticketoem2ref:36

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

Legend:

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

    r87934 r87942  
    348348    }
    349349
    350     /* Assign the global device rate to the stream. */
    351     pStreamShared->State.uTimerIoHz = pThis->uTimerHz;
    352 
    353     /* Set scheduling hint (if available). */
    354     if (pStreamShared->State.uTimerIoHz)
    355         pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz;
    356 
    357350    LogRel2(("HDA: Stream #%RU8 DMA @ 0x%x (%RU32 bytes = %RU64ms total)\n",
    358351             uSD, pStreamShared->u64BDLBase, pStreamShared->u32CBL,
    359              DrvAudioHlpBytesToMilli(pStreamShared->u32CBL, &pStreamShared->State.Cfg.Props)));
    360 
    361     /* Make sure that the chosen Hz rate dividable by the stream's rate. */
    362     if (pStreamShared->State.Cfg.Props.uHz % pStreamShared->State.uTimerIoHz != 0)
    363         LogRel(("HDA: Stream #%RU8 timer Hz rate (%RU32) does not fit to stream #%RU8 timing (%RU32)\n",
    364                 uSD, pStreamShared->State.uTimerIoHz, uSD, pStreamShared->State.Cfg.Props.uHz));
     352             DrvAudioHlpBytesToMilli(pStreamShared->u32CBL, &pStreamR3->State.Mapping.PCMProps)));
    365353
    366354    /* Figure out how many transfer fragments we're going to use for this stream. */
     
    447435     */
    448436
    449     /* Prevent division by zero. */
    450     ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz,
    451                                  ("Timer Hz rate for stream #%RU8 is invalid\n", uSD),
    452                                  pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT);
     437    /* Assign the global device rate to the stream I/O timer as default. */
     438    pStreamShared->State.uTimerIoHz = pThis->uTimerHz;
     439
    453440    /*
    454441     * Determine the transfer Hz the guest OS expects data transfer at.
     
    458445     *
    459446     * Data rate examples:
    460      *   * Windows 10 @ 44,1kHz / 16-bit stereo
    461      *      * Default mode: 448 audio frames -> ~10.15ms) = 1792 byte every ~10ms.
    462      *      * Fast mode:    128 audio frames -> ~ 2.90ms) =  512 byte every ~3ms.
     447     *   * Windows 10 @ 44,1kHz / 16-bit
     448     *      2 channels (stereo):
     449     *          * Default mode: 448 audio frames -> ~10.15ms = 1792 byte every ~10ms.
     450     *          * Fast mode:    128 audio frames -> ~ 2.90ms =  512 byte every ~3ms.
     451     *      6 channels (5.1 surround):
     452     *          * Default mode: Same values as above!
    463453     */
     454
     455    /* Audio data per second the stream needs. */
     456    const uint32_t cbDataPerSec = DrvAudioHlpMilliToBytes(RT_MS_1SEC, &pStreamR3->State.Mapping.PCMProps);
    464457
    465458    /* The transfer Hz depend on the heuristics above, that is,
    466459       how often the guest expects to see a new data transfer. */
    467     unsigned uTransferHz;
     460    uint16_t uTransferHz = 0;
     461
     462    LogRel2(("HDA: Stream #%RU8 needs %RU32 bytes/s audio data\n", uSD, cbDataPerSec));
    468463
    469464    if (pThis->fTransferHeuristicsEnabled) /* Are data transfer heuristics enabled? */
     
    483478            PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
    484479
     480            LogRel2(("HDA: Stream #%RU8 BDLE #%RU8: %R[bdle]\n", uSD, i, &bd));
     481
    485482            /* Position adjustment (still) needed / active? */
    486483            if (cbTransferHeuristicsPosAdjust)
     
    510507
    511508        /* Windows 10's audio driver expects a transfer all ~10.1ms (~1764 bytes), although
    512          * it sets up 1792 bytes per BDLE.
     509         * it sets up multiples of 1792 bytes (896 bytes per channel) per BDLE:
     510         *
     511         *      * 2 (stereo) channels    = 1792
     512         *      * 6 (surrounnd) channels = 1792 * 3 = 5376
     513         *
     514         * Same seems to apply to Windows 7 when using the default setup.
    513515         *
    514516         * I currently don't have any clue why it does this that way, so try to simply detect this
    515          * and alter the value so that we get a somewhat proper audio output. */
    516         if (cbTransferHeuristicsMin == 1792)
    517         {
    518             LogRel2(("HDA: Guest seems to be Windows 10 -- setting a fixed transfer minimum size\n"));
     517         * and alter the value so that we get a somewhat proper audio output.
     518         * Probably alignment?
     519         */
     520        if (cbTransferHeuristicsMin / (1792 / 2 /* Channels */) == pStreamR3->State.Mapping.PCMProps.cChannels)
     521        {
     522            LogRel2(("HDA: Heuristics detected a Windows guest -- setting a fixed transfer minimum size\n"));
    519523            cbTransferHeuristicsMin = 1764;
     524
     525            /* Anything above 5 channels (surround) will need higher timer rates -- otherwise it will be a lot worse. */
     526            if (pStreamR3->State.Mapping.PCMProps.cChannels >= 5)
     527            {
     528                uTransferHz = 100 + ((pStreamR3->State.Mapping.PCMProps.cChannels - 4) * 50); /* Add 50Hz per additional channel. */
     529            }
     530            else /* Stick with 100Hz here. Anything lower will crackle. */
     531                uTransferHz = 100;
     532
     533            pStreamShared->State.uTimerIoHz = 50;
    520534        }
    521535
    522536        /* !!! HACK ALERT END !!! */
    523537
    524         uint32_t msTransferHeuristicsMin = DrvAudioHlpBytesToMilli(cbTransferHeuristicsMin, &pCfg->Props);
    525 
    526         /* Prevent division by zero. */
    527         ASSERT_GUEST_LOGREL_MSG_STMT(msTransferHeuristicsMin,
    528                                      ("Transfer heuristics for stream #%RU8 buggy\n", uSD),
    529                                      msTransferHeuristicsMin = 10 /* ms, equals 100 Hz */);
    530 
    531         uTransferHz = RT_MS_1SEC / msTransferHeuristicsMin;
    532 
    533         LogRel2(("HDA: Stream #%RU8 needs a data transfer at least every %RU64ms (%RU32 bytes) -- transfers run at %u Hz\n",
    534                  uSD, msTransferHeuristicsMin, cbTransferHeuristicsMin, uTransferHz));
    535     }
    536     else
    537     {
    538         /* Use I/O timing rate instead. */
    539         uTransferHz = pStreamShared->State.uTimerIoHz;
     538        else
     539        {
     540            /* Calculate the transfer Hz rate by dividing the guessed transfer data rate by the data rate in ms. */
     541            uTransferHz = cbTransferHeuristicsMin / (cbDataPerSec / RT_MS_1SEC);
     542
     543            /* Make sure that the timer I/O Hz rate is the same in this case, as we can't do any more guessing here. */
     544            pStreamShared->State.uTimerIoHz = uTransferHz;
     545        }
     546
     547        LogRel2(("HDA: Stream #%RU8 seems to need a transfer worth of %RU32 bytes audio data, so trying to run transfers at %uHz\n",
     548                 uSD, cbTransferHeuristicsMin, uTransferHz));
     549    }
     550    else /* Heuristics disabled. */
     551    {
     552        /* Use global timing rate instead. */
     553        uTransferHz = pThis->uTimerHz;
    540554    }
    541555
    542556    if (uTransferHz > 400) /* Anything above 400 Hz looks fishy -- tell the user. */
    543         LogRel(("HDA: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), please re-run with audio debug mode and report a bug\n",
     557        LogRel(("HDA: Warning: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), "
     558                "please re-run with audio debug mode and report a bug\n",
    544559                uSD, uTransferHz));
    545560
     561    LogRel2(("HDA: Stream #%RU8 transfer timer rate is %RU16Hz, I/O timer rate is %RU16Hz\n",
     562             uSD, uTransferHz, pStreamShared->State.uTimerIoHz));
     563
     564    /* Make sure that the chosen transfer Hz rate dividable by the stream's overall data rate. */
     565    ASSERT_GUEST_LOGREL_MSG_STMT(cbDataPerSec % uTransferHz == 0,
     566                                 ("Transfer data rate (%RU32 bytes/s) for stream #%RU8 does not fit to stream timing (%RU32Hz)\n",
     567                                  cbDataPerSec, uSD, uTransferHz),
     568                                 uTransferHz = HDA_TIMER_HZ_DEFAULT);
     569
     570    /* Prevent division by zero. */
     571    ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz,
     572                                 ("I/O timer Hz rate for stream #%RU8 is invalid\n", uSD),
     573                                 pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT);
     574
     575    /* Set I/O scheduling hint for the backends. */
     576    pCfg->Device.cMsSchedulingHint = RT_MS_1SEC / pStreamShared->State.uTimerIoHz;
     577    LogRel2(("HDA: Stream #%RU8 set scheduling hint for the backends to %RU32ms\n", uSD, pCfg->Device.cMsSchedulingHint));
     578
    546579    pStreamShared->State.cbTransferSize =
    547         (pStreamShared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize) / uTransferHz;
     580        (pStreamR3->State.Mapping.PCMProps.uHz * pStreamR3->State.Mapping.cbFrameSize) / 100 /* Hz */;
    548581    ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize,
    549582                                 ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER);
     583
    550584    if (RT_SUCCESS(rc))
    551585    {
     
    568602            const uint64_t uTimerFreq  = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer);
    569603
    570             const double cTicksPerHz   = uTimerFreq  / pStreamShared->State.uTimerIoHz;
     604            const double cTicksPerHz   = uTimerFreq  / uTransferHz;
    571605                  double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk;
    572606
    573             if (pStreamShared->State.uTimerIoHz < uTransferHz)
    574                 cTicksPerByte /= uTransferHz / pStreamShared->State.uTimerIoHz;
     607            if (uTransferHz < 100)
     608                cTicksPerByte /= 100 / uTransferHz;
    575609            else
    576                 cTicksPerByte *= pStreamShared->State.uTimerIoHz / uTransferHz;
     610                cTicksPerByte *= uTransferHz / 100;
    577611
    578612            Assert(cTicksPerByte);
     
    594628            LogRel2(("HDA: Stream #%RU8 is using %uHz I/O timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, "
    595629                     "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n",
    596                      uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamShared->State.Cfg.Props.uHz,
     630                     uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamR3->State.Mapping.PCMProps.uHz,
    597631                     pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks,
    598                      pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pCfg->Props),
    599                      pStreamShared->State.cbTransferSize,  DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize,  &pCfg->Props)));
     632                     pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pStreamR3->State.Mapping.PCMProps),
     633                     pStreamShared->State.cbTransferSize,  DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize,  &pStreamR3->State.Mapping.PCMProps)));
    600634
    601635            /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
     
    630664        const unsigned uTransferHzMin = RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz);
    631665
     666        /* Note: Use pCfg->Props as PCM properties here, as we only want to store the samples we actually need,
     667         *       in other words, skipping the interleaved channels we don't support / need to save space. */
     668
    632669              uint32_t cbCircBuf;
    633670        const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes((RT_MS_1SEC / uTransferHzMin) * 3, &pCfg->Props);
     
    640677        if (cbCircBufGlobal) /* Anything set via CFGM? */
    641678        {
    642 
    643             ASSERT_GUEST_LOGREL_MSG_STMT(DrvAudioHlpBytesIsAligned(cbCircBufGlobal, &pCfg->Props),
    644                                          ("Ring buffer size for stream #%RU8 is misaligned (%zu), setting to default\n", uSD, cbCircBufGlobal),
    645                                          cbCircBufGlobal = cbCircBufDefault);
    646 
    647679            LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU64ms (%RU32 bytes)\n",
    648680                     uSD, DrvAudioHlpBytesToMilli(cbCircBufGlobal, &pCfg->Props), cbCircBufGlobal));
     
    652684        else
    653685            cbCircBuf = cbCircBufDefault;
     686
     687        ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf % (pCfg->Props.cbSample * pCfg->Props.cChannels) == 0,
     688                                     ("Ring buffer size (%RU32) for stream #%RU8 not aligned to mapping's frame size (%RU8)\n",
     689                                      cbCircBuf, uSD, pCfg->Props.cbSample * pCfg->Props.cChannels),
     690                                     rc = VERR_INVALID_PARAMETER);
    654691
    655692        ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf,
     
    16801717                  uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
    16811718                           /* Make sure that we always align the number of bytes when reading to the stream's PCM properties. */
    1682                            cbToReadFromStream = DrvAudioHlpBytesAlign(cbToReadFromStream, &pStreamShared->State.Cfg.Props);
     1719                           cbToReadFromStream = DrvAudioHlpBytesAlign(cbToReadFromStream, &pStreamR3->State.Mapping.PCMProps);
    16831720
    16841721#ifdef LOG_ENABLED
  • trunk/src/VBox/Devices/Audio/HDAStreamMap.cpp

    r82968 r87942  
    123123        pMap->cMappings = 0;
    124124    }
     125
     126    RT_ZERO(pMap->PCMProps);
    125127}
    126128
     
    165167        rc = hdaR3StreamChannelDataInit(&pMapLR->Data, PDMAUDIOSTREAMCHANNELDATA_FLAGS_NONE);
    166168        AssertRC(rc);
     169
     170        memcpy(&pMap->PCMProps, pProps, sizeof(PDMAUDIOPCMPROPS));
    167171    }
    168172    else
  • trunk/src/VBox/Devices/Audio/HDAStreamMap.h

    r82968 r87942  
    2727typedef struct HDASTREAMMAP
    2828{
     29    /** The PCM properties which have been used. */
     30    PDMAUDIOPCMPROPS                PCMProps;
    2931    /** The stream's layout. */
    3032    PDMAUDIOSTREAMLAYOUT            enmLayout;
     33    /** The mapping's overall audio frame size (in bytes).
     34     *  This includes all mappings in \a paMappings. */
    3135    uint8_t                         cbFrameSize;
    3236    /** Number of mappings in paMappings. */
Note: See TracChangeset for help on using the changeset viewer.

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