VirtualBox

Changeset 70278 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Dec 21, 2017 1:54:17 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119873
Message:

Audio/HDA: Implemented recording (and re-routing SDI1 to SDI0) for macOS guests.

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

Legend:

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

    r70251 r70278  
    15291529
    15301530    uint64_t cTicksToNext = pStream->State.cTransferTicks;
    1531 
    1532     Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksTransferred=%RU64, cTicksToNext=%RU64\n",
    1533               pStream->u8SD, cTicksElapsed, cTicksTransferred, cTicksToNext));
    1534 
    1535     Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n",
    1536               pStream->u8SD, pStream->State.cbTransferProcessed, pStream->State.cbTransferChunk, pStream->State.cbTransferSize));
    1537 
    1538     if (cTicksElapsed <= cTicksToNext)
    1539     {
    1540         cTicksToNext = cTicksToNext - cTicksElapsed;
    1541     }
    1542     else /* Catch up. */
    1543     {
    1544         Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",
    1545                  pStream->u8SD, cTicksElapsed, cTicksToNext));
    1546 
    1547         LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n",
    1548                         pStream->u8SD,
    1549                         (TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz) / 1000, (tsNow - pStream->State.tsTransferLast) / 1000));
    1550 
    1551         cTicksToNext = 0;
    1552     }
    1553 
    1554     Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", pStream->u8SD, cTicksToNext));
    1555 
    1556     /* Reset processed data counter. */
    1557     pStream->State.cbTransferProcessed = 0;
    1558 
    1559     /* Re-arm the timer. */
    1560     hdaTimerSet(pThis, tsNow + cTicksToNext, false /* fForce */);
     1531    if (cTicksToNext) /* Only do any calculations if the stream currently is set up for transfers. */
     1532    {
     1533        Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksTransferred=%RU64, cTicksToNext=%RU64\n",
     1534                  pStream->u8SD, cTicksElapsed, cTicksTransferred, cTicksToNext));
     1535
     1536        Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n",
     1537                  pStream->u8SD, pStream->State.cbTransferProcessed, pStream->State.cbTransferChunk, pStream->State.cbTransferSize));
     1538
     1539        if (cTicksElapsed <= cTicksToNext)
     1540        {
     1541            cTicksToNext = cTicksToNext - cTicksElapsed;
     1542        }
     1543        else /* Catch up. */
     1544        {
     1545            Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",
     1546                     pStream->u8SD, cTicksElapsed, cTicksToNext));
     1547
     1548            LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n",
     1549                            pStream->u8SD,
     1550                            (TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz) / 1000, (tsNow - pStream->State.tsTransferLast) / 1000));
     1551
     1552            cTicksToNext = 0;
     1553        }
     1554
     1555        Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", pStream->u8SD, cTicksToNext));
     1556
     1557        /* Reset processed data counter. */
     1558        pStream->State.cbTransferProcessed = 0;
     1559
     1560        /* Re-arm the timer. */
     1561        hdaTimerSet(pThis, tsNow + cTicksToNext, false /* fForce */);
     1562    }
    15611563
    15621564    DEVHDA_UNLOCK_BOTH(pThis);
     
    24812483
    24822484        AssertPtr(pSink->pMixSink);
    2483         LogFlowFunc(("Sink=%s, enmMixerCtl=%d\n", pSink->pMixSink->pszName, enmMixerCtl));
     2485        LogFlowFunc(("Sink=%s, Mixer control=%s\n", pSink->pMixSink->pszName, DrvAudioHlpAudMixerCtlToStr(enmMixerCtl)));
    24842486    }
    24852487    else
     
    25642566        rc = VERR_NOT_FOUND;
    25652567
    2566     LogFlowFunc(("enmMixerCtl=%d, rc=%Rrc\n", enmMixerCtl, rc));
     2568    LogFunc(("Mixer control=%s, rc=%Rrc\n", DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), rc));
    25672569    return rc;
    25682570}
    25692571
    25702572/**
    2571  * Sets a SDn stream number and channel to a particular mixer control.
     2573 * Controls an input / output converter widget, that is, which converter is connected
     2574 * to which stream (and channel).
    25722575 *
    25732576 * @returns IPRT status code.
     
    25812584static DECLCALLBACK(int) hdaMixerControl(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
    25822585{
    2583     LogFlowFunc(("enmMixerCtl=%RU32, uSD=%RU8, uChannel=%RU8\n", enmMixerCtl, uSD, uChannel));
     2586    LogFunc(("enmMixerCtl=%s, uSD=%RU8, uChannel=%RU8\n", DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), uSD, uChannel));
    25842587
    25852588    if (uSD == 0) /* Stream number 0 is reserved. */
    25862589    {
    2587         LogFlowFunc(("Invalid SDn (%RU8) number for mixer control %d, ignoring\n", uSD, enmMixerCtl));
     2590        Log2Func(("Invalid SDn (%RU8) number for mixer control '%s', ignoring\n", uSD, DrvAudioHlpAudMixerCtlToStr(enmMixerCtl)));
    25882591        return VINF_SUCCESS;
    25892592    }
     
    25942597    uSD--;
    25952598
    2596     int rc;
     2599#ifndef VBOX_WITH_AUDIO_HDA_MIC_IN
     2600    /* Only SDI0 (Line-In) is supported. */
     2601    if (   hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN
     2602        && uSD >= 1)
     2603    {
     2604        LogRel2(("HDA: Dedicated Mic-In support not imlpemented / built-in (stream #%RU8), using Line-In (stream #0) instead\n", uSD));
     2605        uSD = 0;
     2606    }
     2607#endif
     2608
     2609    int rc = VINF_SUCCESS;
    25972610
    25982611    PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
    25992612    if (pSink)
    26002613    {
     2614        AssertPtr(pSink->pMixSink);
     2615
     2616        /* If this an output stream, determine the correct SD#. */
    26012617        if (   (uSD < HDA_MAX_SDI)
    26022618            && AudioMixerSinkGetDir(pSink->pMixSink) == AUDMIXSINKDIR_OUTPUT)
     
    26052621        }
    26062622
    2607         LogFlowFunc(("%s: Setting to stream ID=%RU8, channel=%RU8, enmMixerCtl=%RU32\n",
    2608                      pSink->pMixSink->pszName, uSD, uChannel, enmMixerCtl));
     2623        /* Detach the existing stream from the sink. */
     2624        if (   pSink->pStream
     2625            && (   pSink->pStream->u8SD      != uSD
     2626                || pSink->pStream->u8Channel != uChannel)
     2627           )
     2628        {
     2629            LogFunc(("Sink '%s' was assigned to stream #%RU8 (channel %RU8) before\n",
     2630                     pSink->pMixSink->pszName, pSink->pStream->u8SD, pSink->pStream->u8Channel));
     2631
     2632            hdaStreamLock(pSink->pStream);
     2633
     2634            /* Only disable the stream if the stream descriptor # has changed. */
     2635            if (pSink->pStream->u8SD != uSD)
     2636                hdaStreamEnable(pSink->pStream, false);
     2637
     2638            pSink->pStream->pMixSink = NULL;
     2639
     2640            hdaStreamUnlock(pSink->pStream);
     2641
     2642            pSink->pStream = NULL;
     2643        }
    26092644
    26102645        Assert(uSD < HDA_MAX_STREAMS);
    26112646
    2612         PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
    2613         if (pStream)
    2614         {
    2615             hdaStreamLock(pStream);
    2616 
    2617             pSink->pStream    = pStream;
    2618             pStream->pMixSink = pSink;
    2619 
    2620             hdaStreamUnlock(pStream);
    2621 
    2622             rc = VINF_SUCCESS;
    2623         }
    2624         else
    2625         {
    2626             LogRel(("HDA: Guest wanted to assign invalid stream ID=%RU8 (channel %RU8) to mixer control %RU32, skipping\n",
    2627                     uSD, uChannel, enmMixerCtl));
    2628             rc = VERR_INVALID_PARAMETER;
     2647        /* Attach the new stream to the sink.
     2648         * Enabling the stream will be done by the gust via a separate SDnCTL call then. */
     2649        if (pSink->pStream == NULL)
     2650        {
     2651            LogRel2(("HDA: Setting sink '%s' to stream #%RU8 (channel %RU8), mixer control=%s\n",
     2652                     pSink->pMixSink->pszName, uSD, uChannel, DrvAudioHlpAudMixerCtlToStr(enmMixerCtl)));
     2653
     2654            PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
     2655            if (pStream)
     2656            {
     2657                hdaStreamLock(pStream);
     2658
     2659                pSink->pStream = pStream;
     2660
     2661                pStream->u8Channel = uChannel;
     2662                pStream->pMixSink  = pSink;
     2663
     2664                hdaStreamUnlock(pStream);
     2665
     2666                rc = VINF_SUCCESS;
     2667            }
     2668            else
     2669                rc = VERR_NOT_IMPLEMENTED;
    26292670        }
    26302671    }
    26312672    else
    26322673        rc = VERR_NOT_FOUND;
     2674
     2675    if (RT_FAILURE(rc))
     2676        LogRel(("HDA: Converter control for stream #%RU8 (channel %RU8) / mixer control '%s' failed with %Rrc, skipping\n",
     2677                uSD, uChannel, DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), rc));
    26332678
    26342679    LogFlowFuncLeaveRC(rc);
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r70246 r70278  
    388388#endif
    389389
     390    /* Assign the default mixer sink to the stream. */
     391    pStream->pMixSink             = hdaGetDefaultSink(pThis, uSD);
     392
    390393    pStream->State.tsTransferLast = 0;
    391394    pStream->State.tsTransferNext = 0;
     
    442445    int rc = VINF_SUCCESS;
    443446
    444     if (pStream->pMixSink) /* Stream attached to a sink? */
    445     {
    446         AUDMIXSINKCMD enmCmd = fEnable
    447                              ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
    448 
    449         /* First, enable or disable the stream and the stream's sink, if any. */
    450         if (pStream->pMixSink->pMixSink)
    451             rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
    452 
    453         if (   RT_SUCCESS(rc)
    454             && pStream->Dbg.Runtime.fEnabled)
    455         {
    456             if (fEnable)
    457             {
     447    if (!pStream->pMixSink) /* Stream attached to a sink? */
     448    {
     449        AssertMsgFailed(("Stream #%RU8 not has no mixer sink attached\n", pStream->u8SD));
     450        return VERR_WRONG_ORDER;
     451    }
     452
     453    AUDMIXSINKCMD enmCmd = fEnable
     454                         ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
     455
     456    /* First, enable or disable the stream and the stream's sink, if any. */
     457    if (pStream->pMixSink->pMixSink)
     458        rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
     459
     460    if (   RT_SUCCESS(rc)
     461        && pStream->Dbg.Runtime.fEnabled)
     462    {
     463        Assert(DrvAudioHlpPCMPropsAreValid(&pStream->State.Cfg.Props));
     464
     465        if (fEnable)
     466        {
    458467                int rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileStream, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
    459468                                              &pStream->State.Cfg.Props);
     
    463472                                          &pStream->State.Cfg.Props);
    464473                AssertRC(rc2);
    465             }
    466             else
    467             {
     474        }
     475        else
     476        {
    468477                int rc2 = DrvAudioHlpFileClose(pStream->Dbg.Runtime.pFileStream);
    469478                AssertRC(rc2);
     
    471480                rc2 = DrvAudioHlpFileClose(pStream->Dbg.Runtime.pFileDMA);
    472481                AssertRC(rc2);
    473             }
    474482        }
    475483    }
     
    558566bool hdaStreamTransferIsScheduled(PHDASTREAM pStream)
    559567{
    560     AssertPtrReturn(pStream,            false);
     568    if (!pStream)
     569        return false;
     570
    561571    AssertPtrReturn(pStream->pHDAState, false);
    562572
     
    819829    uint32_t cbProcessed = 0;
    820830    uint32_t cbLeft      = cbToProcess;
    821     Assert(cbLeft % pStream->State.cbFrameSize == 0);
    822831
    823832    uint8_t abChunk[HDA_FIFO_MAX + 1];
     
    11561165void hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
    11571166{
     1167    if (!pStream)
     1168        return;
     1169
    11581170    PAUDMIXSINK pSink = NULL;
    11591171    if (   pStream->pMixSink
     
    12311243            uint32_t cbReadable = AudioMixerSinkGetReadable(pSink);
    12321244
    1233             Log3Func(("[SD%RU8] cbReadable=%RU32\n", pStream->u8SD, cbReadable));
     1245            /* How much (guest input) data is available for writing at the moment for the HDA stream? */
     1246            const uint32_t cbFree = hdaStreamGetFree(pStream);
     1247
     1248            Log3Func(("[SD%RU8] cbReadable=%RU32, cbFree=%RU32\n", pStream->u8SD, cbReadable, cbFree));
     1249
     1250            /* Do not write more than the sink can hold at the moment.
     1251             * The host sets the overall pace. */
     1252            if (cbReadable > cbFree)
     1253                cbReadable = cbFree;
    12341254
    12351255            if (cbReadable)
     
    12431263                    AssertRCBreak(rc2);
    12441264
     1265                    if (!cbRead)
     1266                    {
     1267                        AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbReadable));
     1268                        break;
     1269                    }
     1270
    12451271                    /* Write (guest input) data to the stream which was read from stream's sink before. */
    1246                     rc2 = hdaStreamWrite(pStream, abFIFO, cbRead, NULL /* pcbWritten */);
     1272                    uint32_t cbWritten;
     1273                    rc2 = hdaStreamWrite(pStream, abFIFO, cbRead, &cbWritten);
    12471274                    AssertRCBreak(rc2);
     1275
     1276                    if (!cbWritten)
     1277                    {
     1278                        AssertFailed(); /* Should never happen, as we know how much we can write. */
     1279                        break;
     1280                    }
    12481281
    12491282                    Assert(cbReadable >= cbRead);
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