VirtualBox

Changeset 88486 in vbox for trunk/src


Ignore:
Timestamp:
Apr 13, 2021 9:36:47 AM (4 years ago)
Author:
vboxsync
Message:

DrvAudioHostPulseAudio: Mostly done cleaning up stream creation. bugref:9890

File:
1 edited

Legend:

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

    r88480 r88486  
    155155    uint32_t               cUnderflows;
    156156    /** Current latency (in us). */
    157     uint64_t               curLatencyUs;
     157    uint64_t               cUsLatency;
    158158#ifdef LOG_ENABLED
    159159    /** Start time stamp (in us) of stream playback / recording. */
     
    257257
    258258
     259/**
     260 * Wrapper around pa_threaded_mainloop_wait().
     261 */
     262static void drvHostAudioPaMainloopWait(PDRVHOSTPULSEAUDIO pThis)
     263{
     264    /** @todo r=bird: explain this logic. */
     265    if (!pThis->fAbortLoop)
     266        pa_threaded_mainloop_wait(pThis->pMainLoop);
     267    pThis->fAbortLoop = false;
     268}
     269
    259270
    260271/**
     
    302313/**
    303314 * Synchronously wait until an operation completed.
    304  */
    305 static int drvHostAudioPaWaitForEx(PDRVHOSTPULSEAUDIO pThis, pa_operation *pOP, RTMSINTERVAL cMsTimeout)
    306 {
    307     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    308     AssertPtrReturn(pOP,   VERR_INVALID_POINTER);
    309 
    310     int rc = VINF_SUCCESS;
    311 
    312     uint64_t u64StartMs = RTTimeMilliTS();
    313     while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING)
     315 *
     316 * This will consume the pOperation reference.
     317 */
     318static int drvHostAudioPaWaitForEx(PDRVHOSTPULSEAUDIO pThis, pa_operation *pOperation, RTMSINTERVAL cMsTimeout)
     319{
     320    AssertPtrReturn(pOperation, VERR_INVALID_POINTER);
     321
     322    uint64_t const       msStart = RTTimeMilliTS();
     323    pa_operation_state_t enmOpState;
     324    while ((enmOpState = pa_operation_get_state(pOperation)) == PA_OPERATION_RUNNING)
    314325    {
    315326        if (!pThis->fAbortLoop) /** @todo r=bird: I do _not_ get the logic behind this fAbortLoop mechanism, it looks more
     
    321332                || pa_context_get_state(pThis->pContext) != PA_CONTEXT_READY)
    322333            {
    323                 pa_operation_cancel(pOP);
     334                pa_operation_cancel(pOperation);
     335                pa_operation_unref(pOperation);
    324336                LogRel(("PulseAudio: pa_context_get_state context not ready\n"));
    325                 rc = VERR_INVALID_STATE;
     337                return VERR_INVALID_STATE;
     338            }
     339        }
     340        pThis->fAbortLoop = false;
     341
     342        /*
     343         * Note! This timeout business is a bit bogus as pa_threaded_mainloop_wait is indefinite.
     344         */
     345        if (RTTimeMilliTS() - msStart >= cMsTimeout)
     346        {
     347            enmOpState = pa_operation_get_state(pOperation);
     348            if (enmOpState != PA_OPERATION_RUNNING)
    326349                break;
    327             }
    328         }
    329         pThis->fAbortLoop = false;
    330 
    331         uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
    332         if (u64ElapsedMs >= cMsTimeout)
    333         {
    334             pa_operation_cancel(pOP);
    335             rc = VERR_TIMEOUT;
    336             break;
    337         }
    338     }
    339 
    340     pa_operation_unref(pOP);
    341 
    342     return rc;
     350            pa_operation_cancel(pOperation);
     351            pa_operation_unref(pOperation);
     352            return VERR_TIMEOUT;
     353        }
     354    }
     355
     356    pa_operation_unref(pOperation);
     357    if (enmOpState == PA_OPERATION_DONE)
     358        return VINF_SUCCESS;
     359    return VERR_CANCELLED;
    343360}
    344361
     
    710727    LogRel2(("PulseAudio: Warning: Hit underflow #%RU32\n", pStrm->cUnderflows));
    711728
    712     if (   pStrm->cUnderflows  >= 6                /** @todo Make this check configurable. */
    713         && pStrm->curLatencyUs < 2000000 /* 2s */)
    714     {
    715         pStrm->curLatencyUs = (pStrm->curLatencyUs * 3) / 2;
    716 
    717         LogRel2(("PulseAudio: Output latency increased to %RU64ms\n", pStrm->curLatencyUs / 1000 /* ms */));
    718 
    719         pStrm->BufAttr.maxlength = pa_usec_to_bytes(pStrm->curLatencyUs, &pStrm->SampleSpec);
    720         pStrm->BufAttr.tlength   = pa_usec_to_bytes(pStrm->curLatencyUs, &pStrm->SampleSpec);
     729    if (   pStrm->cUnderflows >= 6                /** @todo Make this check configurable. */
     730        && pStrm->cUsLatency < 2000000 /* 2s */)
     731    {
     732        pStrm->cUsLatency = (pStrm->cUsLatency * 3) / 2;
     733
     734        LogRel2(("PulseAudio: Output latency increased to %RU64 us\n", pStrm->cUsLatency));
     735
     736        pStrm->BufAttr.maxlength = pa_usec_to_bytes(pStrm->cUsLatency, &pStrm->SampleSpec);
     737        pStrm->BufAttr.tlength   = pa_usec_to_bytes(pStrm->cUsLatency, &pStrm->SampleSpec);
    721738
    722739        pa_stream_set_buffer_attr(pStream, &pStrm->BufAttr, NULL, NULL);
     
    725742    }
    726743
    727     pa_usec_t curLatencyUs = 0;
    728     pa_stream_get_latency(pStream, &curLatencyUs, NULL /* Neg */);
    729 
    730     LogRel2(("PulseAudio: Latency now is %RU64ms\n", curLatencyUs / 1000 /* ms */));
     744    pa_usec_t cUsLatency = 0;
     745    pa_stream_get_latency(pStream, &cUsLatency, NULL /* Neg */);
     746
     747    LogRel2(("PulseAudio: Latency now is %RU64 us\n", cUsLatency));
    731748
    732749# ifdef LOG_ENABLED
     
    740757    Log2Func(("curPosWrite=%RU64ms, curPosRead=%RU64ms, curTs=%RU64ms, curLatency=%RU64ms (%RU32Hz, %RU8 channels)\n",
    741758              curPosWritesUs / RT_US_1MS_64, curPosReadsUs / RT_US_1MS_64,
    742               curTsUs / RT_US_1MS_64, curLatencyUs / RT_US_1MS_64, pSpec->rate, pSpec->channels));
     759              curTsUs / RT_US_1MS_64, cUsLatency / RT_US_1MS_64, pSpec->rate, pSpec->channels));
    743760# endif
    744761}
     
    797814 * @returns VBox status code.
    798815 * @param   pProps      The PDM audio source properties.
    799  */
    800 static int drvHostAudioPaToAudioProps(PPDMAUDIOPCMPROPS pProps, pa_sample_format_t pulsefmt, uint8_t cChannels, uint32_t uHz)
     816 * @param   enmPulseFmt The PA format.
     817 * @param   cChannels   The number of channels.
     818 * @param   uHz         The frequency.
     819 */
     820static int drvHostAudioPaToAudioProps(PPDMAUDIOPCMPROPS pProps, pa_sample_format_t enmPulseFmt, uint8_t cChannels, uint32_t uHz)
    801821{
    802822    AssertReturn(cChannels > 0, VERR_INVALID_PARAMETER);
    803823    AssertReturn(cChannels < 16, VERR_INVALID_PARAMETER);
    804824
    805     switch (pulsefmt)
     825    switch (enmPulseFmt)
    806826    {
    807827        case PA_SAMPLE_U8:
     
    830850
    831851        default:
    832             AssertLogRelMsgFailed(("PulseAudio: Format (%d) not supported\n", pulsefmt));
     852            AssertLogRelMsgFailed(("PulseAudio: Format (%d) not supported\n", enmPulseFmt));
    833853            return VERR_NOT_SUPPORTED;
    834854    }
     
    844864 * @param   pThis       Our driver instance data.
    845865 * @param   pStreamPA   Our stream data.
    846  * @param   fIn         The direction indicator.
    847866 * @param   pszName     How we name the stream.
    848  * @param   pCfgAcq     Where to return the actual stream properties.  (ASSUMES
    849  *                      same as pCfgAcq on input.)
    850  */
    851 static int drvHostAudioPaStreamOpen(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA, bool fIn,
    852                                     const char *pszName, PPDMAUDIOSTREAMCFG pCfgAcq)
    853 {
    854     int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    855     pa_stream *pStream = NULL;
    856 
    857     pa_threaded_mainloop_lock(pThis->pMainLoop);
    858 
    859     do /* goto avoidance non-loop */
    860     {
    861         pa_sample_spec *pSampleSpec = &pStreamPA->SampleSpec;
    862 
    863         LogFunc(("Opening '%s', rate=%dHz, channels=%d, format=%s\n",
    864                  pszName, pSampleSpec->rate, pSampleSpec->channels,
    865                  pa_sample_format_to_string(pSampleSpec->format)));
    866 
    867         if (!pa_sample_spec_valid(pSampleSpec))
    868         {
    869             LogRel(("PulseAudio: Unsupported sample specification for stream '%s'\n", pszName));
    870             break;
    871         }
    872 
    873         pa_buffer_attr *pBufAttr = &pStreamPA->BufAttr;
    874 
    875         /** @todo r=andy Use pa_stream_new_with_proplist instead. */
    876         if (!(pStream = pa_stream_new(pThis->pContext, pszName, pSampleSpec, NULL /* pa_channel_map */)))
    877         {
    878             LogRel(("PulseAudio: Could not create stream '%s'\n", pszName));
    879             rc = VERR_NO_MEMORY;
    880             break;
    881         }
    882 
     867 * @param   pCfgAcq     The requested stream properties, the Props member is
     868 *                      updated upon successful return.
     869 *
     870 * @note    Caller owns the mainloop lock.
     871 */
     872static int drvHostAudioPaStreamCreateLocked(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA,
     873                                            const char *pszName, PPDMAUDIOSTREAMCFG pCfgAcq)
     874{
     875    /*
     876     * Create the stream.
     877     */
     878    pa_stream *pStream = pa_stream_new(pThis->pContext, pszName, &pStreamPA->SampleSpec, NULL /* pa_channel_map */);
     879    if (!pStream)
     880    {
     881        LogRel(("PulseAudio: Failed to create stream '%s': %s (%d)\n",
     882                pszName, pa_strerror(pa_context_errno(pThis->pContext)), pa_context_errno(pThis->pContext)));
     883        return VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     884    }
     885
     886    /*
     887     * Set the state callback, and in debug builds a few more...
     888     */
    883889#ifdef DEBUG
    884         pa_stream_set_write_callback(       pStream, drvHostAudioPaStreamReqWriteDebugCallback,  pStreamPA);
    885         pa_stream_set_underflow_callback(   pStream, drvHostAudioPaStreamUnderflowDebugCallback, pStreamPA);
    886         if (!fIn) /* Only for output streams. */
    887             pa_stream_set_overflow_callback(pStream, drvHostAudioPaStreamOverflowDebugCallback,  pStreamPA);
     890    pa_stream_set_write_callback(       pStream, drvHostAudioPaStreamReqWriteDebugCallback,  pStreamPA);
     891    pa_stream_set_underflow_callback(   pStream, drvHostAudioPaStreamUnderflowDebugCallback, pStreamPA);
     892    if (pCfgAcq->enmDir == PDMAUDIODIR_OUT)
     893        pa_stream_set_overflow_callback(pStream, drvHostAudioPaStreamOverflowDebugCallback,  pStreamPA);
    888894#endif
    889         pa_stream_set_state_callback(       pStream, drvHostAudioPaStreamStateChangedCallback,   pThis);
    890 
    891         uint32_t flags = PA_STREAM_NOFLAGS;
     895    pa_stream_set_state_callback(       pStream, drvHostAudioPaStreamStateChangedCallback,   pThis);
     896
     897    /*
     898     * Connect the stream.
     899     */
     900    int             rc;
     901    unsigned const  fFlags = PA_STREAM_START_CORKED /* Require explicit starting (uncorking). */
     902                             /* For using pa_stream_get_latency() and pa_stream_get_time(). */
     903                           | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE
    892904#if PA_API_VERSION >= 12
    893         /* XXX */
    894         flags |= PA_STREAM_ADJUST_LATENCY;
     905                           | PA_STREAM_ADJUST_LATENCY
    895906#endif
    896         /* For using pa_stream_get_latency() and pa_stream_get_time(). */
    897         flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
    898 
    899         /* No input/output right away after the stream was started. */
    900         flags |= PA_STREAM_START_CORKED;
    901 
    902         if (fIn)
    903         {
    904             LogFunc(("Input stream attributes: maxlength=%d fragsize=%d\n",
    905                      pBufAttr->maxlength, pBufAttr->fragsize));
    906 
    907             if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags) < 0)
     907                           ;
     908    if (pCfgAcq->enmDir == PDMAUDIODIR_IN)
     909    {
     910        LogFunc(("Input stream attributes: maxlength=%d fragsize=%d\n",
     911                 pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.fragsize));
     912        rc = pa_stream_connect_record(pStream, NULL /*dev*/, &pStreamPA->BufAttr, (pa_stream_flags_t)fFlags);
     913    }
     914    else
     915    {
     916        LogFunc(("Output buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n",
     917                 pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.tlength, pStreamPA->BufAttr.prebuf, pStreamPA->BufAttr.minreq));
     918        rc = pa_stream_connect_playback(pStream, NULL /*dev*/, &pStreamPA->BufAttr, (pa_stream_flags_t)fFlags,
     919                                        NULL /*volume*/, NULL /*sync_stream*/);
     920    }
     921    if (rc >= 0)
     922    {
     923        /*
     924         * Wait for the stream to become ready.
     925         */
     926        uint64_t const nsStart = RTTimeNanoTS();
     927        pa_stream_state_t enmStreamState;
     928        while (   (enmStreamState = pa_stream_get_state(pStream)) != PA_STREAM_READY
     929               && PA_STREAM_IS_GOOD(enmStreamState)
     930               && RTTimeNanoTS() - nsStart < RT_NS_10SEC /* not really timed */ )
     931            drvHostAudioPaMainloopWait(pThis);
     932        if (enmStreamState == PA_STREAM_READY)
     933        {
     934            LogFunc(("Connecting stream took %'RU64 ns\n", RTTimeNanoTS() - nsStart));
     935#ifdef LOG_ENABLED
     936            pStreamPA->tsStartUs = pa_rtclock_now();
     937#endif
     938            /*
     939             * Update the buffer attributes.
     940             */
     941            const pa_buffer_attr *pBufAttribs = pa_stream_get_buffer_attr(pStream);
     942            AssertPtr(pBufAttribs);
     943            if (pBufAttribs)
    908944            {
    909                 LogRel(("PulseAudio: Could not connect input stream '%s': %s\n",
    910                         pszName, pa_strerror(pa_context_errno(pThis->pContext))));
    911                 break;
     945                pStreamPA->BufAttr = *pBufAttribs;
     946                LogFunc(("Obtained %s buffer attributes: maxlength=%RU32 tlength=%RU32 prebuf=%RU32 minreq=%RU32 fragsize=%RU32\n",
     947                         pCfgAcq->enmDir == PDMAUDIODIR_IN ? "input" : "output", pBufAttribs->maxlength, pBufAttribs->tlength,
     948                         pBufAttribs->prebuf, pBufAttribs->minreq, pBufAttribs->fragsize));
     949
     950                /*
     951                 * Convert the sample spec back to PDM speak.
     952                 * Note! This isn't strictly speaking needed as SampleSpec has *not* been
     953                 *       modified since the caller converted it from pCfgReq.
     954                 */
     955                rc = drvHostAudioPaToAudioProps(&pCfgAcq->Props, pStreamPA->SampleSpec.format,
     956                                                pStreamPA->SampleSpec.channels, pStreamPA->SampleSpec.rate);
     957                if (RT_SUCCESS(rc))
     958                {
     959                    pStreamPA->pStream = pStream;
     960                    LogFlowFunc(("returns VINF_SUCCESS\n"));
     961                    return VINF_SUCCESS;
     962                }
    912963            }
     964            else
     965            {
     966                LogRelMax(99, ("PulseAudio: Failed to get buffer attribs for stream '%s': %s (%d)\n",
     967                               pszName, pa_strerror(pa_context_errno(pThis->pContext)), pa_context_errno(pThis->pContext)));
     968                rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     969            }
    913970        }
    914971        else
    915972        {
    916             LogFunc(("Output buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n",
    917                      pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
    918 
    919             if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags,
    920                                            /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
    921             {
    922                 LogRel(("PulseAudio: Could not connect playback stream '%s': %s\n",
    923                         pszName, pa_strerror(pa_context_errno(pThis->pContext))));
    924                 break;
    925             }
    926         }
    927 
    928         /* Wait until the stream is ready. */
    929         pa_stream_state_t enmStreamState;
    930         for (;;)
    931         {
    932             enmStreamState = pa_stream_get_state(pStream);
    933             if (   enmStreamState == PA_STREAM_READY
    934                 || !PA_STREAM_IS_GOOD(enmStreamState))
    935                 break;
    936 
    937             if (!pThis->fAbortLoop)
    938                 pa_threaded_mainloop_wait(pThis->pMainLoop);
    939             pThis->fAbortLoop = false;
    940         }
    941         if (!PA_STREAM_IS_GOOD(enmStreamState))
    942         {
    943             LogRel(("PulseAudio: Failed to initialize stream '%s' (state %ld)\n", pszName, enmStreamState));
    944             break;
    945         }
    946 
    947 #ifdef LOG_ENABLED
    948         pStreamPA->tsStartUs = pa_rtclock_now();
    949 #endif
    950         const pa_buffer_attr *pBufAttrObtained = pa_stream_get_buffer_attr(pStream);
    951         AssertPtrBreak(pBufAttrObtained);
    952         memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr));
    953 
    954         LogFunc(("Obtained %s buffer attributes: tLength=%RU32, maxLength=%RU32, minReq=%RU32, fragSize=%RU32, preBuf=%RU32\n",
    955                  fIn ? "capture" : "playback",
    956                  pBufAttr->tlength, pBufAttr->maxlength, pBufAttr->minreq, pBufAttr->fragsize, pBufAttr->prebuf));
    957 
    958         /*
    959          * Convert it to PDM speak.
    960          */
    961         rc = drvHostAudioPaToAudioProps(&pCfgAcq->Props, pStreamPA->SampleSpec.format,
    962                                         pStreamPA->SampleSpec.channels, pStreamPA->SampleSpec.rate);
    963         if (RT_SUCCESS(rc))
    964         {
    965             pStreamPA->pStream = pStream;
    966             pa_threaded_mainloop_unlock(pThis->pMainLoop);
    967             LogFlowFuncLeaveRC(VINF_SUCCESS);
    968             return VINF_SUCCESS;
    969         }
    970         LogRel(("PulseAudio: Cannot find audio capture format %ld\n", pStreamPA->SampleSpec.format));
    971     } while (0);
    972 
    973     /* We failed. */
    974     if (pStream)
     973            LogRelMax(99, ("PulseAudio: Failed to initialize stream '%s': state=%d, waited %'RU64 ns\n",
     974                           pszName, enmStreamState, RTTimeNanoTS() - nsStart));
     975            rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     976        }
    975977        pa_stream_disconnect(pStream);
    976 
    977     pa_threaded_mainloop_unlock(pThis->pMainLoop);
    978 
    979     if (pStream)
    980         pa_stream_unref(pStream);
    981     LogFlowFuncLeaveRC(rc);
    982     return rc;
    983 }
    984 
    985 
    986 static int drvHostAudioPaCreateStreamOut(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA,
    987                                          PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, const char *pszName)
    988 {
    989     Assert(pCfgReq->enmDir == PDMAUDIODIR_OUT);
    990 
    991     pStreamPA->curLatencyUs      = PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize) * RT_US_1MS;
    992     uint32_t const cbLatency     = pa_usec_to_bytes(pStreamPA->curLatencyUs, &pStreamPA->SampleSpec);
    993     pStreamPA->BufAttr.tlength   = cbLatency;
    994     pStreamPA->BufAttr.maxlength = -1; /* Let the PulseAudio server choose the biggest size it can handle. */
    995     pStreamPA->BufAttr.prebuf    = cbLatency;
    996     pStreamPA->BufAttr.minreq    = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod);
    997     LogRel2(("PulseAudio: Initial output latency is %RU64 ms (%RU32 bytes)\n", pStreamPA->curLatencyUs / RT_US_1MS, cbLatency));
    998     LogFunc(("Requested: BufAttr tlength=%RU32, maxLength=%RU32, minReq=%RU32\n",
    999              pStreamPA->BufAttr.tlength, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq));
    1000 
    1001     int rc = drvHostAudioPaStreamOpen(pThis, pStreamPA, false /* fIn */, pszName, pCfgReq);
    1002     if (RT_SUCCESS(rc))
    1003     {
    1004         /* Note! BuffAttr contains the acquired values now.*/
    1005         LogFunc(("Acquired: BufAttr tlength=%RU32, maxLength=%RU32, minReq=%RU32\n",
    1006                  pStreamPA->BufAttr.tlength, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq));
    1007         pCfgAcq->Backend.cFramesPeriod        = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.minreq);
    1008         pCfgAcq->Backend.cFramesBufferSize    = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.tlength);
    1009         pCfgAcq->Backend.cFramesPreBuffering  = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.prebuf);
    1010     }
    1011     return rc;
    1012 }
    1013 
    1014 
    1015 static int drvHostAudioPaCreateStreamIn(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM  pStreamPA,
    1016                                         PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, const char *pszName)
    1017 {
    1018     Assert(pCfgReq->enmDir == PDMAUDIODIR_IN);
    1019 
    1020     pStreamPA->BufAttr.fragsize  = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod);
    1021     pStreamPA->BufAttr.maxlength = -1; /* Let the PulseAudio server choose the biggest size it can handle. */
    1022 
    1023     int rc = drvHostAudioPaStreamOpen(pThis, pStreamPA, true /* fIn */, pszName, pCfgAcq);
    1024     if (RT_SUCCESS(rc))
    1025     {
    1026         /* Note! BuffAttr contains the acquired values now.*/
    1027         pCfgAcq->Backend.cFramesPeriod       = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.fragsize);
    1028         pCfgAcq->Backend.cFramesBufferSize   = pStreamPA->BufAttr.maxlength != UINT32_MAX /* paranoia */
    1029                                              ? PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.maxlength)
    1030                                              : pCfgAcq->Backend.cFramesPeriod * 2 /* whatever */;
    1031         pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod;
    1032     }
     978    }
     979    else
     980    {
     981        LogRelMax(99, ("PulseAudio: Could not connect %s stream '%s': %s (%d/%d)\n",
     982                       pCfgAcq->enmDir == PDMAUDIODIR_IN ? "input" : "output",
     983                       pszName, pa_strerror(pa_context_errno(pThis->pContext)), pa_context_errno(pThis->pContext), rc));
     984        rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     985    }
     986
     987    pa_stream_unref(pStream);
     988    Assert(RT_FAILURE_NP(rc));
     989    LogFlowFunc(("returns %Rrc\n", rc));
    1033990    return rc;
    1034991}
     
    10471004    AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
    10481005    AssertReturn(pCfgReq->enmDir == PDMAUDIODIR_IN || pCfgReq->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
     1006    Assert(PDMAudioStrmCfgEquals(pCfgReq, pCfgAcq));
    10491007    int rc;
    10501008
    10511009    /*
    1052      * Common prep bits.
     1010     * Prepare name, sample spec and the stream instance data.
    10531011     */
    10541012    char szName[256];
     
    10711029    {
    10721030        /*
    1073          * Do some direction specific buffer config and call drvHostAudioPaStreamOpen.
     1031         * Set up buffer attributes according to the stream type.
    10741032         */
     1033        pStreamPA->BufAttr.maxlength = -1; /* Let the PulseAudio server choose the biggest size it can handle. */
    10751034        if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    1076             rc = drvHostAudioPaCreateStreamIn (pThis, pStreamPA, pCfgReq, pCfgAcq, szName);
     1035        {
     1036            pStreamPA->BufAttr.fragsize  = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod);
     1037            LogFunc(("Requesting: BufAttr: fragsize=%RU32 maxlength=-1\n", pStreamPA->BufAttr.fragsize));
     1038        }
    10771039        else
    1078             rc = drvHostAudioPaCreateStreamOut(pThis, pStreamPA, pCfgReq, pCfgAcq, szName);
    1079 
    1080         PDMAudioStrmCfgCopy(&pStreamPA->Cfg, pCfgAcq);
     1040        {
     1041            pStreamPA->cUsLatency        = PDMAudioPropsFramesToMicro(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
     1042            pStreamPA->BufAttr.tlength   = pa_usec_to_bytes(pStreamPA->cUsLatency, &pStreamPA->SampleSpec);
     1043            pStreamPA->BufAttr.prebuf    = pStreamPA->BufAttr.tlength;
     1044            pStreamPA->BufAttr.minreq    = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod);
     1045            LogRel2(("PulseAudio: Initial output latency is %RU64 us (%RU32 bytes)\n",
     1046                     pStreamPA->cUsLatency, pStreamPA->BufAttr.tlength));
     1047            LogFunc(("Requesting: BufAttr: tlength=%RU32 maxLength=%RU32 minReq=%RU32 maxlength=-1\n",
     1048                     pStreamPA->BufAttr.tlength, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq));
     1049        }
     1050
     1051        /*
     1052         * Do the actual PA stream creation.
     1053         */
     1054        pa_threaded_mainloop_lock(pThis->pMainLoop);
     1055        rc = drvHostAudioPaStreamCreateLocked(pThis, pStreamPA, szName, pCfgAcq);
     1056        pa_threaded_mainloop_unlock(pThis->pMainLoop);
     1057        if (RT_SUCCESS(rc))
     1058        {
     1059            /*
     1060             * Set the acquired stream config according to the actual buffer
     1061             * attributes we got and the stream type.
     1062             */
     1063            if (pCfgReq->enmDir == PDMAUDIODIR_IN)
     1064            {
     1065                pCfgAcq->Backend.cFramesPeriod       = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.fragsize);
     1066                pCfgAcq->Backend.cFramesBufferSize   = pStreamPA->BufAttr.maxlength != UINT32_MAX /* paranoia */
     1067                                                     ? PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.maxlength)
     1068                                                     : pCfgAcq->Backend.cFramesPeriod * 2 /* whatever */;
     1069                pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod;
     1070            }
     1071            else
     1072            {
     1073                pCfgAcq->Backend.cFramesPeriod        = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.minreq);
     1074                pCfgAcq->Backend.cFramesBufferSize    = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.tlength);
     1075                pCfgAcq->Backend.cFramesPreBuffering  = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamPA->BufAttr.prebuf);
     1076            }
     1077            PDMAudioStrmCfgCopy(&pStreamPA->Cfg, pCfgAcq);
     1078        }
    10811079    }
    10821080    else
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