VirtualBox

Changeset 87964 in vbox


Ignore:
Timestamp:
Mar 4, 2021 11:34:43 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143067
Message:

Forward ported r143064 from 6.1: DevHDA: Try be as exact as possible wrt timer period when basing it on the buffer descriptor setup. Glitches are gone for me now, even in debug builds. bugref:9890

File:
1 edited

Legend:

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

    r87962 r87964  
    357357
    358358    /* Figure out how many transfer fragments we're going to use for this stream. */
    359     uint8_t cTransferFragments = pStreamShared->u16LVI + 1;
     359    uint32_t cTransferFragments = pStreamShared->u16LVI + 1;
    360360    if (cTransferFragments <= 1)
    361         LogRel(("HDA: Warning: Stream #%RU8 transfer fragments (%RU8) invalid -- buggy guest audio driver!\n",
     361        LogRel(("HDA: Warning: Stream #%RU8 transfer fragments (%RU16) invalid -- buggy guest audio driver!\n",
    362362                uSD, pStreamShared->u16LVI));
    363363
     
    426426            /* Initialize position adjustment counter. */
    427427            pStreamShared->State.cfPosAdjustDefault = cfPosAdjust;
    428             pStreamShared->State.cfPosAdjustLeft    = pStreamShared->State.cfPosAdjustDefault;
    429 
    430             LogRel2(("HDA: Position adjustment for stream #%RU8 active (%RU32 frames)\n",
    431                      uSD, pStreamShared->State.cfPosAdjustDefault));
    432         }
    433     }
    434 
    435     Log3Func(("[SD%RU8] cfPosAdjust=%RU32, cFragments=%RU8\n", uSD, cfPosAdjust, cTransferFragments));
     428            pStreamShared->State.cfPosAdjustLeft    = cfPosAdjust;
     429            LogRel2(("HDA: Position adjustment for stream #%RU8 active (%RU32 frames)\n", uSD, cfPosAdjust));
     430        }
     431    }
     432
     433    Log3Func(("[SD%RU8] cfPosAdjust=%RU32, cFragments=%RU32\n", uSD, cfPosAdjust, cTransferFragments));
    436434
    437435    /*
     
    460458    const uint32_t cbDataPerSec = DrvAudioHlpMilliToBytes(RT_MS_1SEC, &pStreamR3->State.Mapping.PCMProps);
    461459
     460    /* This is used to indicate whether we're done or should the uTimerIoHz as fallback. */
     461    rc = VINF_SUCCESS;
     462
    462463    /* The transfer Hz depend on the heuristics above, that is,
    463464       how often the guest expects to see a new data transfer. */
    464     uint16_t uTransferHz = 0;
     465    ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz,
     466                                 ("I/O timer Hz rate for stream #%RU8 is invalid\n", uSD),
     467                                 pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT);
     468    unsigned uTransferHz = pStreamShared->State.uTimerIoHz;
    465469
    466470    LogRel2(("HDA: Stream #%RU8 needs %RU32 bytes/s audio data\n", uSD, cbDataPerSec));
     
    468472    if (pThis->fTransferHeuristicsEnabled) /* Are data transfer heuristics enabled? */
    469473    {
    470 
    471         /* Use the whole CBL as a starting point.
    472          * This basically ASSUMES that we have one consequtive buffer with only one interrupt at the end. */
    473         uint32_t cbTransferHeuristicsMin       = pStreamShared->u32CBL;
    474 
    475474        /* Don't take frames (as bytes) into account which are part of the position adjustment. */
    476475        uint32_t cbTransferHeuristicsPosAdjust = pStreamShared->State.cfPosAdjustDefault * pStreamR3->State.Mapping.cbFrameSize;
    477 
    478         HDABDLEDESC bd;
    479         uint32_t    cbTransferHeuristicsCur = 0;
    480         for (uint8_t i = 0; i < cTransferFragments; i++)
    481         {
     476        uint32_t cbTransferHeuristics          = 0;
     477        uint32_t cbTransferHeuristicsCur       = 0;
     478        uint32_t cBufferIrqs                   = 0;
     479        for (uint32_t i = 0; i < cTransferFragments; i++)
     480        {
     481            /** @todo wrong read type!   */
     482            HDABDLEDESC bd = { 0, 0, 0 };
    482483            PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
    483484
     
    501502            {
    502503                cbTransferHeuristicsCur += bd.u32BufSize;
    503                 cbTransferHeuristicsMin  = RT_MIN(cbTransferHeuristicsCur, cbTransferHeuristicsMin);
    504                 cbTransferHeuristicsCur  = 0;
     504                if (   cbTransferHeuristicsCur == cbTransferHeuristics
     505                    || !cbTransferHeuristics)
     506                    cbTransferHeuristics = cbTransferHeuristicsCur;
     507                else
     508                {
     509                    /** @todo r=bird: you need to find the smallest common denominator here, not
     510                     *        just the minimum.  Ignoring this for now as windows has two equal
     511                     *        sized buffers both with IOC set. */
     512                    LogRel(("HDA: Uneven IRQ buffer config; i=%u cbCur=%#x cbMin=%#x.\n", i, cbTransferHeuristicsCur, cbTransferHeuristics));
     513                    cbTransferHeuristics = RT_MIN(cbTransferHeuristicsCur, cbTransferHeuristics);
     514                }
     515                cbTransferHeuristicsCur = 0;
     516                cBufferIrqs++;
    505517            }
    506518            else /* No interrupt expected -> add it to the former BDLE size. */
     
    508520        }
    509521
    510         /* !!! HACK ALERT BEGIN !!! */
    511 
    512         /* Windows 10's audio driver expects a transfer all ~10.1ms (~1764 bytes), although
    513          * it sets up multiples of 1792 bytes (896 bytes per channel) per BDLE:
     522        /*
     523         * IFF the guest is using buffer IRQ, configure the timer to
     524         * the lowest common denominator of those IRQ periods.
    514525         *
    515          *      * 2 (stereo) channels    = 1792
    516          *      * 6 (surrounnd) channels = 1792 * 3 = 5376
    517          *
    518          * Same seems to apply to Windows 7 when using the default setup.
    519          *
    520          * I currently don't have any clue why it does this that way, so try to simply detect this
    521          * and alter the value so that we get a somewhat proper audio output.
    522          * Probably alignment?
     526         * Otherwise, fall back on using default timer I/O Hz (set above).
    523527         */
    524         if (cbTransferHeuristicsMin / (1792 / 2 /* Channels */) == pStreamR3->State.Mapping.PCMProps.cChannels)
    525         {
    526             LogRel2(("HDA: Heuristics detected a Windows guest -- setting a fixed transfer minimum size\n"));
    527             cbTransferHeuristicsMin = 1764;
    528 
    529             /* Anything above 5 channels (surround) will need higher timer rates -- otherwise it will be a lot worse. */
    530             if (pStreamR3->State.Mapping.PCMProps.cChannels >= 5)
    531             {
    532                 uTransferHz = 100 + ((pStreamR3->State.Mapping.PCMProps.cChannels - 4) * 50); /* Add 50Hz per additional channel. */
    533             }
    534             else /* Stick with 100Hz here. Anything lower will crackle. */
    535                 uTransferHz = 100;
    536 
    537             pStreamShared->State.uTimerIoHz = 50;
    538         }
    539 
    540         /* !!! HACK ALERT END !!! */
    541 
    542         else
    543         {
    544             /* Calculate the transfer Hz rate by dividing the guessed transfer data rate by the data rate in ms. */
    545             uTransferHz = cbTransferHeuristicsMin / (cbDataPerSec / RT_MS_1SEC);
    546 
    547             /* Make sure that the timer I/O Hz rate is the same in this case, as we can't do any more guessing here. */
    548             pStreamShared->State.uTimerIoHz = uTransferHz;
    549         }
    550 
    551         LogRel2(("HDA: Stream #%RU8 seems to need a transfer worth of %RU32 bytes audio data, so trying to run transfers at %uHz\n",
    552                  uSD, cbTransferHeuristicsMin, uTransferHz));
    553     }
    554     else /* Heuristics disabled. */
    555     {
    556         /* Use global timing rate instead. */
    557         uTransferHz = pThis->uTimerHz;
     528        if (cBufferIrqs > 0 && cbTransferHeuristics > 1)
     529        {
     530            pStreamShared->State.cbTransferSize  = cbTransferHeuristics;
     531            pStreamShared->State.cbTransferChunk = cbTransferHeuristics; /* no chunking */
     532            ASSERT_GUEST_LOGREL_MSG(DrvAudioHlpBytesIsAligned(cbTransferHeuristics, &pCfg->Props),
     533                                    ("We arrived at a misaligned transfer size for stream #%RU8: %#x (%u)\n",
     534                                     uSD, cbTransferHeuristics, cbTransferHeuristics));
     535
     536            /* Convert to timer ticks. */
     537            uint64_t const cTimerTicksPerSec = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer);
     538            uint64_t const cbTransferPerSec  = RT_MAX(pStreamShared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize,
     539                                                      4096 /* zero div prevention: min is 6kHz, picked 4k in case I'm mistaken */);
     540            pStreamShared->State.cTicksPerByte = (cTimerTicksPerSec + cbTransferPerSec / 2) / cbTransferPerSec;
     541            AssertStmt(pStreamShared->State.cTicksPerByte, pStreamShared->State.cTicksPerByte = 4096);
     542
     543            pStreamShared->State.cTransferTicks = (cTimerTicksPerSec * cbTransferHeuristics + cbTransferPerSec / 2)
     544                                                / cbTransferPerSec;
     545
     546            /* Estimate timer HZ for the circular buffer setup. */
     547            uTransferHz = cbTransferPerSec * 1000 / cbTransferHeuristics;
     548            LogRel2(("HDA: Stream #%RU8 needs a data transfer at least every %RU64 ticks / %RU32 bytes / approx %u.%03u Hz\n",
     549                     uSD, pStreamShared->State.cTransferTicks, cbTransferHeuristics, uTransferHz / 1000, uTransferHz % 1000));
     550            uTransferHz /= 1000;
     551
     552            /* Indicate that we're done with period calculation. */
     553            rc = VINF_ALREADY_INITIALIZED;
     554        }
    558555    }
    559556
    560557    if (uTransferHz > 400) /* Anything above 400 Hz looks fishy -- tell the user. */
    561         LogRel(("HDA: Warning: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), "
    562                 "please re-run with audio debug mode and report a bug\n",
     558        LogRel(("HDA: Warning: Calculated transfer Hz rate for stream #%RU8 looks incorrect (%u), please re-run with audio debug mode and report a bug\n",
    563559                uSD, uTransferHz));
    564 
    565     LogRel2(("HDA: Stream #%RU8 transfer timer rate is %RU16Hz, I/O timer rate is %RU16Hz\n",
    566              uSD, uTransferHz, pStreamShared->State.uTimerIoHz));
    567 
    568     /* Make sure that the chosen transfer Hz rate dividable by the stream's overall data rate. */
    569     ASSERT_GUEST_LOGREL_MSG_STMT(cbDataPerSec % uTransferHz == 0,
    570                                  ("Transfer data rate (%RU32 bytes/s) for stream #%RU8 does not fit to stream timing (%RU32Hz)\n",
    571                                   cbDataPerSec, uSD, uTransferHz),
    572                                  uTransferHz = HDA_TIMER_HZ_DEFAULT);
    573 
    574     /* Prevent division by zero. */
    575     ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerIoHz,
    576                                  ("I/O timer Hz rate for stream #%RU8 is invalid\n", uSD),
    577                                  pStreamShared->State.uTimerIoHz = HDA_TIMER_HZ_DEFAULT);
    578560
    579561    /* Set I/O scheduling hint for the backends. */
     
    581563    LogRel2(("HDA: Stream #%RU8 set scheduling hint for the backends to %RU32ms\n", uSD, pCfg->Device.cMsSchedulingHint));
    582564
    583     pStreamShared->State.cbTransferSize =
    584         (pStreamR3->State.Mapping.PCMProps.uHz * pStreamR3->State.Mapping.cbFrameSize) / 100 /* Hz */;
    585     ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize,
    586                                  ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER);
     565    if (rc != VINF_ALREADY_INITIALIZED && RT_SUCCESS(rc))
     566    {
     567        /*
     568         * Transfer heuristics disabled or failed.
     569         */
     570        Assert(uTransferHz == pStreamShared->State.uTimerIoHz);
     571        LogRel2(("HDA: Stream #%RU8 transfer timer and I/O timer rate is %u Hz.\n", uSD, uTransferHz));
     572
     573        /* Make sure that the chosen transfer Hz rate dividable by the stream's overall data rate. */
     574        ASSERT_GUEST_LOGREL_MSG_STMT(cbDataPerSec % uTransferHz == 0,
     575                                     ("Transfer data rate (%RU32 bytes/s) for stream #%RU8 does not fit to stream timing (%u Hz)\n",
     576                                      cbDataPerSec, uSD, uTransferHz),
     577                                     uTransferHz = HDA_TIMER_HZ_DEFAULT);
     578
     579        pStreamShared->State.cbTransferSize = (pStreamR3->State.Mapping.PCMProps.uHz * pStreamR3->State.Mapping.cbFrameSize)
     580                                            / uTransferHz;
     581        ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize,
     582                                     ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER);
     583        if (RT_SUCCESS(rc))
     584        {
     585            /*
     586             * Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
     587             * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects.
     588             *
     589             * As we don't do chunked transfers the moment, the chunk size equals the overall transfer size.
     590             */
     591            pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize;
     592            ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk,
     593                                         ("Transfer chunk for stream #%RU8 is invalid\n", uSD),
     594                                         rc = VERR_INVALID_PARAMETER);
     595            if (RT_SUCCESS(rc))
     596            {
     597                /* Make sure that the transfer chunk does not exceed the overall transfer size. */
     598                AssertStmt(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize,
     599                           pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize);
     600
     601                const uint64_t uTimerFreq  = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer);
     602
     603                const double cTicksPerHz   = uTimerFreq  / uTransferHz;
     604
     605                double       cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk;
     606                if (uTransferHz < 100)
     607                    cTicksPerByte /= 100 / uTransferHz;
     608                else
     609                    cTicksPerByte *= uTransferHz / 100;
     610                Assert(cTicksPerByte);
     611
     612#define HDA_ROUND_NEAREST(a_X) ((a_X) >= 0 ? (uint32_t)((a_X) + 0.5) : (uint32_t)((a_X) - 0.5))
     613
     614                /* Calculate the timer ticks per byte for this stream. */
     615                pStreamShared->State.cTicksPerByte = HDA_ROUND_NEAREST(cTicksPerByte);
     616                Assert(pStreamShared->State.cTicksPerByte);
     617
     618                const double cTransferTicks = pStreamShared->State.cbTransferChunk * cTicksPerByte;
     619
     620                /* Calculate timer ticks per transfer. */
     621                pStreamShared->State.cTransferTicks = HDA_ROUND_NEAREST(cTransferTicks);
     622                Assert(pStreamShared->State.cTransferTicks);
     623#undef HDA_ROUND_NEAREST
     624
     625                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",
     626                         uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamR3->State.Mapping.PCMProps.uHz,
     627                         pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks,
     628                         pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pStreamR3->State.Mapping.PCMProps),
     629                         pStreamShared->State.cbTransferSize,  DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize,  &pStreamR3->State.Mapping.PCMProps)));
     630            }
     631        }
     632    }
    587633
    588634    if (RT_SUCCESS(rc))
    589635    {
     636        /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
     637        hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
     638
     639#ifdef LOG_ENABLED
     640        hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
     641#endif
     642
    590643        /*
    591          * Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
    592          * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects.
    593          *
    594          * As we don't do chunked transfers the moment, the chunk size equals the overall transfer size.
     644         * Set up internal ring buffer.
    595645         */
    596         pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize;
    597         ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk,
    598                                      ("Transfer chunk for stream #%RU8 is invalid\n", uSD),
    599                                      rc = VERR_INVALID_PARAMETER);
    600         if (RT_SUCCESS(rc))
    601         {
    602             /* Make sure that the transfer chunk does not exceed the overall transfer size. */
    603             AssertStmt(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize,
    604                        pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize);
    605 
    606             const uint64_t uTimerFreq  = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer);
    607 
    608             const double cTicksPerHz   = uTimerFreq  / uTransferHz;
    609                   double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk;
    610 
    611             if (uTransferHz < 100)
    612                 cTicksPerByte /= 100 / uTransferHz;
    613             else
    614                 cTicksPerByte *= uTransferHz / 100;
    615 
    616             Assert(cTicksPerByte);
    617 
    618 #define HDA_ROUND_NEAREST(a_X) ((a_X) >= 0 ? (uint32_t)((a_X) + 0.5) : (uint32_t)((a_X) - 0.5)) /** @todo r=andy Do we have rounding in IPRT? */
    619 
    620             /* Calculate the timer ticks per byte for this stream. */
    621             pStreamShared->State.cTicksPerByte = HDA_ROUND_NEAREST(cTicksPerByte);
    622             Assert(pStreamShared->State.cTicksPerByte);
    623 
    624             const double cTransferTicks = pStreamShared->State.cbTransferChunk * cTicksPerByte;
    625 
    626             /* Calculate timer ticks per transfer. */
    627             pStreamShared->State.cTransferTicks = HDA_ROUND_NEAREST(cTransferTicks);
    628             Assert(pStreamShared->State.cTransferTicks);
    629 
    630 #undef HDA_ROUND_NEAREST
    631 
    632             LogRel2(("HDA: Stream #%RU8 is using %uHz I/O timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, "
    633                      "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n",
    634                      uSD, pStreamShared->State.uTimerIoHz, (uint64_t)cTicksPerHz, pStreamR3->State.Mapping.PCMProps.uHz,
    635                      pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks,
    636                      pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pStreamR3->State.Mapping.PCMProps),
    637                      pStreamShared->State.cbTransferSize,  DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize,  &pStreamR3->State.Mapping.PCMProps)));
    638 
    639             /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
    640             hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
    641 
    642 #ifdef LOG_ENABLED
    643             hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
    644 #endif
    645         }
    646     }
    647 
    648     /*
    649      * Set up internal ring buffer.
    650      */
    651     if (RT_SUCCESS(rc))
    652     {
     646
    653647        /* (Re-)Allocate the stream's internal DMA buffer,
    654648         * based on the timing *and* PCM properties we just got above. */
     
    667661         * We always use triple the minimum timing of both timings for safety (triple buffering),
    668662         * otherwise we risk running into buffer overflows.
     663         *
     664         * Note: Use pCfg->Props as PCM properties here, as we only want to store the samples we actually need,
     665         *       in other words, skipping the interleaved channels we don't support / need to save space.
    669666         */
    670         const unsigned uTransferHzMin = RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz);
    671 
    672         /* Note: Use pCfg->Props as PCM properties here, as we only want to store the samples we actually need,
    673          *       in other words, skipping the interleaved channels we don't support / need to save space. */
    674 
    675               uint32_t cbCircBuf;
     667
     668        const unsigned uTransferHzMin   = RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz);
    676669        const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes((RT_MS_1SEC / uTransferHzMin) * 3, &pCfg->Props);
    677670
     
    679672                 uSD, DrvAudioHlpBytesToMilli(cbCircBufDefault, &pCfg->Props), cbCircBufDefault));
    680673
     674        uint32_t cbCircBuf;
    681675        uint32_t cbCircBufGlobal = DrvAudioHlpMilliToBytes(  hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN
    682676                                                           ? pThis->cbCircBufInMs : pThis->cbCircBufOutMs, &pCfg->Props);
     
    695689                                      cbCircBuf, uSD, pCfg->Props.cbSample * pCfg->Props.cChannels),
    696690                                     rc = VERR_INVALID_PARAMETER);
    697 
    698         ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf,
    699                                      ("Ring buffer size for stream #%RU8 is invalid\n", uSD),
     691        ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf, ("Ring buffer size for stream #%RU8 is invalid\n", uSD),
    700692                                     rc = VERR_INVALID_PARAMETER);
    701693        if (RT_SUCCESS(rc))
     
    707699
    708700#ifdef VBOX_WITH_DTRACE
    709     VBOXDD_HDA_STREAM_SETUP((uint32_t)uSD, rc, /** @todo uHz - 44100 and such */ 0,
     701    VBOXDD_HDA_STREAM_SETUP((uint32_t)uSD, rc, pStreamShared->State.Cfg.Props.uHz,
    710702                            pStreamShared->State.cTransferTicks, pStreamShared->State.cbTransferSize);
    711703#endif
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