VirtualBox

儲存庫 vbox 的更動 88292


忽略:
時間撮記:
2021-3-25 下午01:17:32 (4 年 以前)
作者:
vboxsync
svn:sync-xref-src-repo-rev:
143503
訊息:

DrvAudio: Some stream creation cleanups. bugref:9890

位置:
trunk/src/VBox/Devices/Audio
檔案:
修改 3 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Devices/Audio/AudioHlp.cpp

    r88269 r88292  
    586586
    587587/**
     588 * Creates a debug file structure and opens a file for it, extended version.
     589 *
     590 * @returns VBox status code.
     591 * @param   ppFile      Where to return the debug file instance on success.
     592 * @param   enmType     The file type.
     593 * @param   pszDir      The directory to open the file in.
     594 * @param   pszName     The base filename.
     595 * @param   iInstance   The device/driver instance.
     596 * @param   fFilename   PDMAUDIOFILENAME_FLAGS_XXX.
     597 * @param   fCreate     PDMAUDIOFILE_FLAGS_XXX.
     598 * @param   pProps      PCM audio properties for the file.
     599 * @param   fOpen       RTFILE_O_XXX or PDMAUDIOFILE_DEFAULT_OPEN_FLAGS.
     600 */
     601int AudioHlpFileCreateAndOpenEx(PPDMAUDIOFILE *ppFile, PDMAUDIOFILETYPE enmType, const char *pszDir, const char *pszName,
     602                                uint32_t iInstance, uint32_t fFilename, uint32_t fCreate,
     603                                PCPDMAUDIOPCMPROPS pProps, uint64_t fOpen)
     604{
     605    char szFile[RTPATH_MAX];
     606    int rc = AudioHlpFileNameGet(szFile, sizeof(szFile), pszDir, pszName, iInstance, enmType, fFilename);
     607    if (RT_SUCCESS(rc))
     608    {
     609        PPDMAUDIOFILE pFile = NULL;
     610        rc = AudioHlpFileCreate(enmType, szFile, fCreate, &pFile);
     611        if (RT_SUCCESS(rc))
     612        {
     613            rc = AudioHlpFileOpen(pFile, fOpen, pProps);
     614            if (RT_SUCCESS(rc))
     615            {
     616                *ppFile = pFile;
     617                return rc;
     618            }
     619            AudioHlpFileDestroy(pFile);
     620        }
     621    }
     622    *ppFile = NULL;
     623    return rc;
     624}
     625
     626/**
     627 * Creates a debug wav-file structure and opens a file for it, default flags.
     628 *
     629 * @returns VBox status code.
     630 * @param   ppFile      Where to return the debug file instance on success.
     631 * @param   pszDir      The directory to open the file in.
     632 * @param   pszName     The base filename.
     633 * @param   iInstance   The device/driver instance.
     634 * @param   pProps      PCM audio properties for the file.
     635 */
     636int AudioHlpFileCreateAndOpen(PPDMAUDIOFILE *ppFile, const char *pszDir, const char *pszName,
     637                              uint32_t iInstance, PCPDMAUDIOPCMPROPS pProps)
     638{
     639    return AudioHlpFileCreateAndOpenEx(ppFile, PDMAUDIOFILETYPE_WAV, pszDir, pszName, iInstance,
     640                                       PDMAUDIOFILENAME_FLAGS_NONE, PDMAUDIOFILE_FLAGS_NONE,
     641                                       pProps, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS);
     642}
     643
     644
     645/**
    588646 * Closes an audio file.
    589647 *
  • trunk/src/VBox/Devices/Audio/AudioHlp.h

    r88235 r88292  
    6262/** @name Audio file methods.
    6363 * @{ */
     64int     AudioHlpFileCreateAndOpen(PPDMAUDIOFILE *ppFile, const char *pszDir, const char *pszName,
     65                                  uint32_t iInstance, PCPDMAUDIOPCMPROPS pProps);
     66int     AudioHlpFileCreateAndOpenEx(PPDMAUDIOFILE *ppFile, PDMAUDIOFILETYPE enmType, const char *pszDir, const char *pszName,
     67                                    uint32_t iInstance, uint32_t fFilename, uint32_t fCreate,
     68                                    PCPDMAUDIOPCMPROPS pProps, uint64_t fOpen);
    6469int     AudioHlpFileCreate(PDMAUDIOFILETYPE enmType, const char *pszFile, uint32_t fFlags, PPDMAUDIOFILE *ppFile);
    6570void    AudioHlpFileDestroy(PPDMAUDIOFILE pFile);
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r88278 r88292  
    686686
    687687/**
    688  * Initializes an audio stream with a given host and guest stream configuration.
    689  *
    690  * @returns IPRT status code.
    691  * @param   pThis               Pointer to driver instance.
    692  * @param   pStream             Stream to initialize.
    693  * @param   pCfgHost            Stream configuration to use for the host side (backend).
    694  * @param   pCfgGuest           Stream configuration to use for the guest side.
    695  */
    696 static int drvAudioStreamInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream,
    697                                       PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest)
    698 {
    699     AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
    700     AssertPtrReturn(pStream,   VERR_INVALID_POINTER);
    701     AssertPtrReturn(pCfgHost,  VERR_INVALID_POINTER);
    702     AssertPtrReturn(pCfgGuest, VERR_INVALID_POINTER);
    703 
    704     /*
    705      * Init host stream.
    706      */
    707     pStream->uMagic = PDMAUDIOSTREAM_MAGIC;
    708 
    709     /* Set the host's default audio data layout. */
    710     pCfgHost->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
    711 
    712 #ifdef LOG_ENABLED
    713     LogFunc(("[%s] Requested host format:\n", pStream->szName));
    714     PDMAudioStrmCfgLog(pCfgHost);
    715 #endif
    716 
    717     LogRel2(("Audio: Creating stream '%s'\n", pStream->szName));
    718     LogRel2(("Audio: Guest %s format for '%s': %RU32Hz, %u%s, %RU8 channel%s\n",
    719              pCfgGuest->enmDir == PDMAUDIODIR_IN ? "recording" : "playback", pStream->szName,
    720              pCfgGuest->Props.uHz, PDMAudioPropsSampleBits(&pCfgGuest->Props), pCfgGuest->Props.fSigned ? "S" : "U",
    721              PDMAudioPropsChannels(&pCfgGuest->Props), PDMAudioPropsChannels(&pCfgGuest->Props) == 1 ? "" : "s"));
    722     LogRel2(("Audio: Requested host %s format for '%s': %RU32Hz, %u%s, %RU8 channel%s\n",
    723              pCfgHost->enmDir == PDMAUDIODIR_IN ? "recording" : "playback", pStream->szName,
    724              pCfgHost->Props.uHz, PDMAudioPropsSampleBits(&pCfgHost->Props), pCfgHost->Props.fSigned ? "S" : "U",
    725              PDMAudioPropsChannels(&pCfgHost->Props), PDMAudioPropsChannels(&pCfgHost->Props) == 1 ? "" : "s"));
    726 
    727     PDMAUDIOSTREAMCFG CfgHostAcq;
    728     int rc = drvAudioStreamCreateInternalBackend(pThis, pStream, pCfgHost, &CfgHostAcq);
    729     if (RT_FAILURE(rc))
    730         return rc;
    731 
    732     LogFunc(("[%s] Acquired host format:\n",  pStream->szName));
    733     PDMAudioStrmCfgLog(&CfgHostAcq);
    734     LogRel2(("Audio: Acquired host %s format for '%s': %RU32Hz, %u%s, %RU8 channel%s\n",
    735              CfgHostAcq.enmDir == PDMAUDIODIR_IN ? "recording" : "playback",  pStream->szName,
    736              CfgHostAcq.Props.uHz, PDMAudioPropsSampleBits(&CfgHostAcq.Props), CfgHostAcq.Props.fSigned ? "S" : "U",
    737              PDMAudioPropsChannels(&CfgHostAcq.Props), PDMAudioPropsChannels(&CfgHostAcq.Props) == 1 ? "" : "s"));
    738     Assert(PDMAudioPropsAreValid(&CfgHostAcq.Props));
    739 
    740     /* Let the user know if the backend changed some of the tweakable values. */
    741     if (CfgHostAcq.Backend.cFramesBufferSize != pCfgHost->Backend.cFramesBufferSize)
    742         LogRel2(("Audio: Backend changed buffer size from %RU64ms (%RU32 frames) to %RU64ms (%RU32 frames)\n",
    743                  PDMAudioPropsFramesToMilli(&pCfgHost->Props, pCfgHost->Backend.cFramesBufferSize), pCfgHost->Backend.cFramesBufferSize,
    744                  PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize), CfgHostAcq.Backend.cFramesBufferSize));
    745 
    746     if (CfgHostAcq.Backend.cFramesPeriod != pCfgHost->Backend.cFramesPeriod)
    747         LogRel2(("Audio: Backend changed period size from %RU64ms (%RU32 frames) to %RU64ms (%RU32 frames)\n",
    748                  PDMAudioPropsFramesToMilli(&pCfgHost->Props, pCfgHost->Backend.cFramesPeriod), pCfgHost->Backend.cFramesPeriod,
    749                  PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPeriod), CfgHostAcq.Backend.cFramesPeriod));
    750 
    751     if (CfgHostAcq.Backend.cFramesPreBuffering != pCfgHost->Backend.cFramesPreBuffering)
    752         LogRel2(("Audio: Backend changed pre-buffering size from %RU64ms (%RU32 frames) to %RU64ms (%RU32 frames)\n",
    753                  PDMAudioPropsFramesToMilli(&pCfgHost->Props, pCfgHost->Backend.cFramesPreBuffering), pCfgHost->Backend.cFramesPreBuffering,
    754                  PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering), CfgHostAcq.Backend.cFramesPreBuffering));
    755 
    756     /*
    757      * Configure host buffers.
    758      */
    759 
    760     /* Check if the backend did return sane values and correct if necessary.
    761      * Should never happen with our own backends, but you never know ... */
    762     if (CfgHostAcq.Backend.cFramesBufferSize < CfgHostAcq.Backend.cFramesPreBuffering)
    763     {
    764         LogRel2(("Audio: Warning: Pre-buffering size (%RU32 frames) of stream '%s' does not match buffer size (%RU32 frames), "
    765                  "setting pre-buffering size to %RU32 frames\n",
    766                  CfgHostAcq.Backend.cFramesPreBuffering, pStream->szName, CfgHostAcq.Backend.cFramesBufferSize, CfgHostAcq.Backend.cFramesBufferSize));
    767         CfgHostAcq.Backend.cFramesPreBuffering = CfgHostAcq.Backend.cFramesBufferSize;
    768     }
    769 
    770     if (CfgHostAcq.Backend.cFramesPeriod > CfgHostAcq.Backend.cFramesBufferSize)
    771     {
    772         LogRel2(("Audio: Warning: Period size (%RU32 frames) of stream '%s' does not match buffer size (%RU32 frames), setting to %RU32 frames\n",
    773                  CfgHostAcq.Backend.cFramesPeriod, pStream->szName, CfgHostAcq.Backend.cFramesBufferSize, CfgHostAcq.Backend.cFramesBufferSize));
    774         CfgHostAcq.Backend.cFramesPeriod = CfgHostAcq.Backend.cFramesBufferSize;
    775     }
    776 
    777     uint64_t msBufferSize = PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize);
    778     LogRel2(("Audio: Buffer size of stream '%s' is %RU64ms (%RU32 frames)\n",
    779              pStream->szName, msBufferSize, CfgHostAcq.Backend.cFramesBufferSize));
    780 
    781     /* If no own pre-buffer is set, let the backend choose. */
    782     uint64_t msPreBuf = PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering);
    783     LogRel2(("Audio: Pre-buffering size of stream '%s' is %RU64ms (%RU32 frames)\n",
    784              pStream->szName, msPreBuf, CfgHostAcq.Backend.cFramesPreBuffering));
    785 
    786     /* Make sure the configured buffer size by the backend at least can hold the configured latency. */
    787     const uint32_t msPeriod = PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPeriod);
    788 
    789     LogRel2(("Audio: Period size of stream '%s' is %RU64ms (%RU32 frames)\n",
    790              pStream->szName, msPeriod, CfgHostAcq.Backend.cFramesPeriod));
    791 
    792     if (   pCfgGuest->Device.cMsSchedulingHint             /* Any scheduling hint set? */
    793         && pCfgGuest->Device.cMsSchedulingHint > msPeriod) /* This might lead to buffer underflows. */
    794     {
    795         LogRel(("Audio: Warning: Scheduling hint of stream '%s' is bigger (%RU64ms) than used period size (%RU64ms)\n",
    796                 pStream->szName, pCfgGuest->Device.cMsSchedulingHint, msPeriod));
    797     }
    798 
    799     /* Destroy any former mixing buffer. */
    800     AudioMixBufDestroy(&pStream->Host.MixBuf);
    801 
    802     rc = AudioMixBufInit(&pStream->Host.MixBuf, pStream->szName, &CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize);
    803     AssertRC(rc);
    804 
    805     /* Make a copy of the acquired host stream configuration. */
    806     rc = PDMAudioStrmCfgCopy(&pStream->Host.Cfg, &CfgHostAcq);
    807     AssertRC(rc);
    808 
    809     /*
    810      * Init guest stream.
    811      */
    812 
    813     if (pCfgGuest->Device.cMsSchedulingHint)
    814         LogRel2(("Audio: Stream '%s' got a scheduling hint of %RU32ms (%RU32 bytes)\n",
    815                  pStream->szName, pCfgGuest->Device.cMsSchedulingHint,
    816                  PDMAudioPropsMilliToBytes(&pCfgGuest->Props, pCfgGuest->Device.cMsSchedulingHint)));
    817 
    818     /* Destroy any former mixing buffer. */
    819     AudioMixBufDestroy(&pStream->Guest.MixBuf);
    820 
    821     /* Set the guests's default audio data layout. */
    822     pCfgGuest->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
    823 
    824     rc = AudioMixBufInit(&pStream->Guest.MixBuf, pStream->szName, &pCfgGuest->Props, CfgHostAcq.Backend.cFramesBufferSize);
    825     AssertRC(rc);
    826 
    827     /* Make a copy of the guest stream configuration. */
    828     rc = PDMAudioStrmCfgCopy(&pStream->Guest.Cfg, pCfgGuest);
    829     AssertRC(rc);
    830 
    831     if (RT_FAILURE(rc))
    832         LogRel(("Audio: Creating stream '%s' failed with %Rrc\n", pStream->szName, rc));
    833 
    834     if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
    835     {
    836         /* Host (Parent) -> Guest (Child). */
    837         rc = AudioMixBufLinkTo(&pStream->Host.MixBuf, &pStream->Guest.MixBuf);
    838         AssertRC(rc);
    839     }
    840     else
    841     {
    842         /* Guest (Parent) -> Host (Child). */
    843         rc = AudioMixBufLinkTo(&pStream->Guest.MixBuf, &pStream->Host.MixBuf);
    844         AssertRC(rc);
    845     }
    846 
    847 #ifdef VBOX_WITH_STATISTICS
    848     char szStatName[255];
    849 
    850     if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
    851     {
    852         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesCaptured", pStream->szName);
    853         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalFramesCaptured,
    854                                   szStatName, STAMUNIT_COUNT, "Total frames played.");
    855         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesCaptured", pStream->szName);
    856         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalTimesCaptured,
    857                                   szStatName, STAMUNIT_COUNT, "Total number of playbacks.");
    858         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesRead", pStream->szName);
    859         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalFramesRead,
    860                                   szStatName, STAMUNIT_COUNT, "Total frames read.");
    861         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesRead", pStream->szName);
    862         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalTimesRead,
    863                                   szStatName, STAMUNIT_COUNT, "Total number of reads.");
    864     }
    865     else if (pCfgGuest->enmDir == PDMAUDIODIR_OUT)
    866     {
    867         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesPlayed", pStream->szName);
    868         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalFramesPlayed,
    869                                   szStatName, STAMUNIT_COUNT, "Total frames played.");
    870 
    871         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesPlayed", pStream->szName);
    872         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalTimesPlayed,
    873                                   szStatName, STAMUNIT_COUNT, "Total number of playbacks.");
    874         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesWritten", pStream->szName);
    875         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalFramesWritten,
    876                                   szStatName, STAMUNIT_COUNT, "Total frames written.");
    877 
    878         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesWritten", pStream->szName);
    879         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalTimesWritten,
    880                                   szStatName, STAMUNIT_COUNT, "Total number of writes.");
    881     }
    882     else
    883         AssertFailed();
    884 #endif
    885 
    886     LogFlowFunc(("[%s] Returning %Rrc\n", pStream->szName, rc));
    887     return rc;
    888 }
    889 
    890 /**
    891688 * Frees an audio stream and its allocated resources.
    892689 *
     
    24102207
    24112208/**
     2209 * Worker for drvAudioStreamInitInternal and drvAudioStreamReInitInternal that
     2210 * creates the backend (host driver) side of an audio stream.
     2211 *
     2212 * @returns VBox status code.
     2213 * @param   pThis               Pointer to driver instance.
     2214 * @param   pStream             Audio stream to create the backend side for.
     2215 * @param   pCfgReq             Requested audio stream configuration to use for stream creation.
     2216 * @param   pCfgAcq             Acquired audio stream configuration returned by the backend.
     2217 *
     2218 * @note    Configuration precedence for requested audio stream configuration (first has highest priority, if set):
     2219 *          - per global extra-data
     2220 *          - per-VM extra-data
     2221 *          - requested configuration (by pCfgReq)
     2222 *          - default value
     2223 */
     2224static int drvAudioStreamCreateInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream,
     2225                                               PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     2226{
     2227    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     2228    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     2229    AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
     2230    AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
     2231
     2232    AssertMsg((pStream->fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED) == 0,
     2233              ("Stream '%s' already initialized in backend\n", pStream->szName));
     2234
     2235    /* Get the right configuration for the stream to be created. */
     2236    PDRVAUDIOCFG pDrvCfg = pCfgReq->enmDir == PDMAUDIODIR_IN ? &pThis->In.Cfg : &pThis->Out.Cfg;
     2237
     2238    /* Fill in the tweakable parameters into the requested host configuration.
     2239     * All parameters in principle can be changed and returned by the backend via the acquired configuration. */
     2240
     2241    /*
     2242     * PCM
     2243     */
     2244    if (PDMAudioPropsSampleSize(&pDrvCfg->Props) != 0) /* Anything set via custom extra-data? */
     2245    {
     2246        PDMAudioPropsSetSampleSize(&pCfgReq->Props, PDMAudioPropsSampleSize(&pDrvCfg->Props));
     2247        LogRel2(("Audio: Using custom sample size of %RU8 bytes for stream '%s'\n",
     2248                 PDMAudioPropsSampleSize(&pCfgReq->Props), pStream->szName));
     2249    }
     2250
     2251    if (pDrvCfg->Props.uHz) /* Anything set via custom extra-data? */
     2252    {
     2253        pCfgReq->Props.uHz = pDrvCfg->Props.uHz;
     2254        LogRel2(("Audio: Using custom Hz rate %RU32 for stream '%s'\n", pCfgReq->Props.uHz, pStream->szName));
     2255    }
     2256
     2257    if (pDrvCfg->uSigned != UINT8_MAX) /* Anything set via custom extra-data? */
     2258    {
     2259        pCfgReq->Props.fSigned = RT_BOOL(pDrvCfg->uSigned);
     2260        LogRel2(("Audio: Using custom %s sample format for stream '%s'\n",
     2261                 pCfgReq->Props.fSigned ? "signed" : "unsigned", pStream->szName));
     2262    }
     2263
     2264    if (pDrvCfg->uSwapEndian != UINT8_MAX) /* Anything set via custom extra-data? */
     2265    {
     2266        pCfgReq->Props.fSwapEndian = RT_BOOL(pDrvCfg->uSwapEndian);
     2267        LogRel2(("Audio: Using custom %s endianess for samples of stream '%s'\n",
     2268                 pCfgReq->Props.fSwapEndian ? "swapped" : "original", pStream->szName));
     2269    }
     2270
     2271    if (PDMAudioPropsChannels(&pDrvCfg->Props) != 0) /* Anything set via custom extra-data? */
     2272    {
     2273        PDMAudioPropsSetChannels(&pCfgReq->Props, PDMAudioPropsChannels(&pDrvCfg->Props));
     2274        LogRel2(("Audio: Using custom %RU8 channel(s) for stream '%s'\n", PDMAudioPropsChannels(&pDrvCfg->Props), pStream->szName));
     2275    }
     2276
     2277    /* Validate PCM properties. */
     2278    if (!AudioHlpPcmPropsAreValid(&pCfgReq->Props))
     2279    {
     2280        LogRel(("Audio: Invalid custom PCM properties set for stream '%s', cannot create stream\n", pStream->szName));
     2281        return VERR_INVALID_PARAMETER;
     2282    }
     2283
     2284    /*
     2285     * Period size
     2286     */
     2287    const char *pszWhat = "device-specific";
     2288    if (pDrvCfg->uPeriodSizeMs)
     2289    {
     2290        pCfgReq->Backend.cFramesPeriod = PDMAudioPropsMilliToFrames(&pCfgReq->Props, pDrvCfg->uPeriodSizeMs);
     2291        pszWhat = "custom";
     2292    }
     2293
     2294    if (!pCfgReq->Backend.cFramesPeriod) /* Set default period size if nothing explicitly is set. */
     2295    {
     2296        pCfgReq->Backend.cFramesPeriod = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 150 /*ms*/);
     2297        pszWhat = "default";
     2298    }
     2299
     2300    LogRel2(("Audio: Using %s period size %RU64 ms / %RU32 frames for stream '%s'\n",
     2301             pszWhat, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod),
     2302             pCfgReq->Backend.cFramesPeriod, pStream->szName));
     2303
     2304    /*
     2305     * Buffer size
     2306     */
     2307    pszWhat = "device-specific";
     2308    if (pDrvCfg->uBufferSizeMs)
     2309    {
     2310        pCfgReq->Backend.cFramesBufferSize = PDMAudioPropsMilliToFrames(&pCfgReq->Props, pDrvCfg->uBufferSizeMs);
     2311        pszWhat = "custom";
     2312    }
     2313
     2314    if (!pCfgReq->Backend.cFramesBufferSize) /* Set default buffer size if nothing explicitly is set. */
     2315    {
     2316        pCfgReq->Backend.cFramesBufferSize = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 300 /*ms*/);
     2317        pszWhat = "default";
     2318    }
     2319
     2320    LogRel2(("Audio: Using %s buffer size %RU64 ms / %RU32 frames for stream '%s'\n",
     2321             pszWhat, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize),
     2322             pCfgReq->Backend.cFramesBufferSize, pStream->szName));
     2323
     2324    /*
     2325     * Pre-buffering size
     2326     */
     2327    pszWhat = "device-specific";
     2328    if (pDrvCfg->uPreBufSizeMs != UINT32_MAX) /* Anything set via global / per-VM extra-data? */
     2329    {
     2330        pCfgReq->Backend.cFramesPreBuffering = PDMAudioPropsMilliToFrames(&pCfgReq->Props, pDrvCfg->uPreBufSizeMs);
     2331        pszWhat = "custom";
     2332    }
     2333    else /* No, then either use the default or device-specific settings (if any). */
     2334    {
     2335        if (pCfgReq->Backend.cFramesPreBuffering == UINT32_MAX) /* Set default pre-buffering size if nothing explicitly is set. */
     2336        {
     2337            /* For pre-buffering to finish the buffer at least must be full one time. */
     2338            pCfgReq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesBufferSize;
     2339            pszWhat = "default";
     2340        }
     2341    }
     2342
     2343    LogRel2(("Audio: Using %s pre-buffering size %RU64 ms / %RU32 frames for stream '%s'\n",
     2344             pszWhat, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPreBuffering),
     2345             pCfgReq->Backend.cFramesPreBuffering, pStream->szName));
     2346
     2347    /*
     2348     * Validate input.
     2349     */
     2350    if (pCfgReq->Backend.cFramesBufferSize < pCfgReq->Backend.cFramesPeriod)
     2351    {
     2352        LogRel(("Audio: Error for stream '%s': Buffering size (%RU64ms) must not be smaller than the period size (%RU64ms)\n",
     2353                pStream->szName, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize),
     2354                PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod)));
     2355        return VERR_INVALID_PARAMETER;
     2356    }
     2357
     2358    if (   pCfgReq->Backend.cFramesPreBuffering != UINT32_MAX /* Custom pre-buffering set? */
     2359        && pCfgReq->Backend.cFramesPreBuffering)
     2360    {
     2361        if (pCfgReq->Backend.cFramesBufferSize < pCfgReq->Backend.cFramesPreBuffering)
     2362        {
     2363            LogRel(("Audio: Error for stream '%s': Buffering size (%RU64ms) must not be smaller than the pre-buffering size (%RU64ms)\n",
     2364                    pStream->szName, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPreBuffering),
     2365                    PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize)));
     2366            return VERR_INVALID_PARAMETER;
     2367        }
     2368    }
     2369
     2370    /*
     2371     * Make the acquired host configuration the requested host configuration initially,
     2372     * in case the backend does not report back an acquired configuration.
     2373     */
     2374    /** @todo r=bird: This is conveniently not documented in the interface... */
     2375    int rc = PDMAudioStrmCfgCopy(pCfgAcq, pCfgReq);
     2376    if (RT_FAILURE(rc))
     2377    {
     2378        LogRel(("Audio: Creating stream '%s' with an invalid backend configuration not possible, skipping\n",
     2379                pStream->szName));
     2380        return rc;
     2381    }
     2382
     2383    /*
     2384     * Call the host driver to create the stream.
     2385     */
     2386    AssertPtr(pThis->pHostDrvAudio);
     2387    if (pThis->pHostDrvAudio)
     2388        rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStream->pvBackend, pCfgReq, pCfgAcq);
     2389    else
     2390        rc = VERR_PDM_NO_ATTACHED_DRIVER;
     2391    if (RT_FAILURE(rc))
     2392    {
     2393        if (rc == VERR_NOT_SUPPORTED)
     2394            LogRel2(("Audio: Creating stream '%s' in backend not supported\n", pStream->szName));
     2395        else if (rc == VERR_AUDIO_STREAM_COULD_NOT_CREATE)
     2396            LogRel2(("Audio: Stream '%s' could not be created in backend because of missing hardware / drivers\n", pStream->szName));
     2397        else
     2398            LogRel(("Audio: Creating stream '%s' in backend failed with %Rrc\n", pStream->szName, rc));
     2399        return rc;
     2400    }
     2401
     2402    /* Validate acquired configuration. */
     2403    char szTmp[PDMAUDIOPROPSTOSTRING_MAX];
     2404    AssertLogRelMsgReturn(AudioHlpStreamCfgIsValid(pCfgAcq),
     2405                          ("Audio: Creating stream '%s' returned an invalid backend configuration (%s), skipping\n",
     2406                           pStream->szName, PDMAudioPropsToString(&pCfgAcq->Props, szTmp, sizeof(szTmp))),
     2407                          VERR_INVALID_PARAMETER);
     2408
     2409    /* Let the user know that the backend changed one of the values requested above. */
     2410    if (pCfgAcq->Backend.cFramesBufferSize != pCfgReq->Backend.cFramesBufferSize)
     2411        LogRel2(("Audio: Buffer size overwritten by backend for stream '%s' (now %RU64ms, %RU32 frames)\n",
     2412                 pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesBufferSize), pCfgAcq->Backend.cFramesBufferSize));
     2413
     2414    if (pCfgAcq->Backend.cFramesPeriod != pCfgReq->Backend.cFramesPeriod)
     2415        LogRel2(("Audio: Period size overwritten by backend for stream '%s' (now %RU64ms, %RU32 frames)\n",
     2416                 pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesPeriod), pCfgAcq->Backend.cFramesPeriod));
     2417
     2418    /* Was pre-buffering requested, but the acquired configuration from the backend told us something else? */
     2419    if (pCfgReq->Backend.cFramesPreBuffering)
     2420    {
     2421        if (pCfgAcq->Backend.cFramesPreBuffering != pCfgReq->Backend.cFramesPreBuffering)
     2422            LogRel2(("Audio: Pre-buffering size overwritten by backend for stream '%s' (now %RU64ms, %RU32 frames)\n",
     2423                     pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesPreBuffering), pCfgAcq->Backend.cFramesPreBuffering));
     2424
     2425        if (pCfgAcq->Backend.cFramesPreBuffering > pCfgAcq->Backend.cFramesBufferSize)
     2426        {
     2427            pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesBufferSize;
     2428            LogRel2(("Audio: Pre-buffering size bigger than buffer size for stream '%s', adjusting to %RU64ms (%RU32 frames)\n",
     2429                     pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesPreBuffering), pCfgAcq->Backend.cFramesPreBuffering));
     2430        }
     2431    }
     2432    else if (pCfgReq->Backend.cFramesPreBuffering == 0) /* Was the pre-buffering requested as being disabeld? Tell the users. */
     2433    {
     2434        LogRel2(("Audio: Pre-buffering is disabled for stream '%s'\n", pStream->szName));
     2435        pCfgAcq->Backend.cFramesPreBuffering = 0;
     2436    }
     2437
     2438    /* Sanity for detecting buggy backends. */
     2439    AssertMsgReturn(pCfgAcq->Backend.cFramesPeriod < pCfgAcq->Backend.cFramesBufferSize,
     2440                    ("Acquired period size must be smaller than buffer size\n"),
     2441                    VERR_INVALID_PARAMETER);
     2442    AssertMsgReturn(pCfgAcq->Backend.cFramesPreBuffering <= pCfgAcq->Backend.cFramesBufferSize,
     2443                    ("Acquired pre-buffering size must be smaller or as big as the buffer size\n"),
     2444                    VERR_INVALID_PARAMETER);
     2445
     2446    pStream->fStatus |= PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED;
     2447
     2448    return VINF_SUCCESS;
     2449}
     2450
     2451
     2452/**
     2453 * Worker for drvAudioStreamCreate that initializes the audio stream.
     2454 *
     2455 * @returns IPRT status code.
     2456 * @param   pThis               Pointer to driver instance.
     2457 * @param   pStream             Stream to initialize.
     2458 * @param   pCfgHost            Stream configuration to use for the host side (backend).
     2459 * @param   pCfgGuest           Stream configuration to use for the guest side.
     2460 */
     2461static int drvAudioStreamInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream,
     2462                                      PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest)
     2463{
     2464    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
     2465    AssertPtrReturn(pStream,   VERR_INVALID_POINTER);
     2466    AssertPtrReturn(pCfgHost,  VERR_INVALID_POINTER);
     2467    AssertPtrReturn(pCfgGuest, VERR_INVALID_POINTER);
     2468
     2469    /*
     2470     * Init host stream.
     2471     */
     2472    pStream->uMagic = PDMAUDIOSTREAM_MAGIC;
     2473
     2474    /* Set the host's default audio data layout. */
     2475    pCfgHost->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
     2476
     2477#ifdef LOG_ENABLED
     2478    LogFunc(("[%s] Requested host format:\n", pStream->szName));
     2479    PDMAudioStrmCfgLog(pCfgHost);
     2480#endif
     2481
     2482    LogRel2(("Audio: Creating stream '%s'\n", pStream->szName));
     2483    LogRel2(("Audio: Guest %s format for '%s': %RU32Hz, %u%s, %RU8 channel%s\n",
     2484             pCfgGuest->enmDir == PDMAUDIODIR_IN ? "recording" : "playback", pStream->szName,
     2485             pCfgGuest->Props.uHz, PDMAudioPropsSampleBits(&pCfgGuest->Props), pCfgGuest->Props.fSigned ? "S" : "U",
     2486             PDMAudioPropsChannels(&pCfgGuest->Props), PDMAudioPropsChannels(&pCfgGuest->Props) == 1 ? "" : "s"));
     2487    LogRel2(("Audio: Requested host %s format for '%s': %RU32Hz, %u%s, %RU8 channel%s\n",
     2488             pCfgHost->enmDir == PDMAUDIODIR_IN ? "recording" : "playback", pStream->szName,
     2489             pCfgHost->Props.uHz, PDMAudioPropsSampleBits(&pCfgHost->Props), pCfgHost->Props.fSigned ? "S" : "U",
     2490             PDMAudioPropsChannels(&pCfgHost->Props), PDMAudioPropsChannels(&pCfgHost->Props) == 1 ? "" : "s"));
     2491
     2492    PDMAUDIOSTREAMCFG CfgHostAcq;
     2493    int rc = drvAudioStreamCreateInternalBackend(pThis, pStream, pCfgHost, &CfgHostAcq);
     2494    if (RT_FAILURE(rc))
     2495        return rc;
     2496
     2497    LogFunc(("[%s] Acquired host format:\n",  pStream->szName));
     2498    PDMAudioStrmCfgLog(&CfgHostAcq);
     2499    LogRel2(("Audio: Acquired host %s format for '%s': %RU32Hz, %u%s, %RU8 channel%s\n",
     2500             CfgHostAcq.enmDir == PDMAUDIODIR_IN ? "recording" : "playback",  pStream->szName,
     2501             CfgHostAcq.Props.uHz, PDMAudioPropsSampleBits(&CfgHostAcq.Props), CfgHostAcq.Props.fSigned ? "S" : "U",
     2502             PDMAudioPropsChannels(&CfgHostAcq.Props), PDMAudioPropsChannels(&CfgHostAcq.Props) == 1 ? "" : "s"));
     2503    Assert(PDMAudioPropsAreValid(&CfgHostAcq.Props));
     2504
     2505    /* Let the user know if the backend changed some of the tweakable values. */
     2506    if (CfgHostAcq.Backend.cFramesBufferSize != pCfgHost->Backend.cFramesBufferSize)
     2507        LogRel2(("Audio: Backend changed buffer size from %RU64ms (%RU32 frames) to %RU64ms (%RU32 frames)\n",
     2508                 PDMAudioPropsFramesToMilli(&pCfgHost->Props, pCfgHost->Backend.cFramesBufferSize), pCfgHost->Backend.cFramesBufferSize,
     2509                 PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize), CfgHostAcq.Backend.cFramesBufferSize));
     2510
     2511    if (CfgHostAcq.Backend.cFramesPeriod != pCfgHost->Backend.cFramesPeriod)
     2512        LogRel2(("Audio: Backend changed period size from %RU64ms (%RU32 frames) to %RU64ms (%RU32 frames)\n",
     2513                 PDMAudioPropsFramesToMilli(&pCfgHost->Props, pCfgHost->Backend.cFramesPeriod), pCfgHost->Backend.cFramesPeriod,
     2514                 PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPeriod), CfgHostAcq.Backend.cFramesPeriod));
     2515
     2516    if (CfgHostAcq.Backend.cFramesPreBuffering != pCfgHost->Backend.cFramesPreBuffering)
     2517        LogRel2(("Audio: Backend changed pre-buffering size from %RU64ms (%RU32 frames) to %RU64ms (%RU32 frames)\n",
     2518                 PDMAudioPropsFramesToMilli(&pCfgHost->Props, pCfgHost->Backend.cFramesPreBuffering), pCfgHost->Backend.cFramesPreBuffering,
     2519                 PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering), CfgHostAcq.Backend.cFramesPreBuffering));
     2520
     2521    /*
     2522     * Configure host buffers.
     2523     */
     2524
     2525    /* Check if the backend did return sane values and correct if necessary.
     2526     * Should never happen with our own backends, but you never know ... */
     2527    if (CfgHostAcq.Backend.cFramesBufferSize < CfgHostAcq.Backend.cFramesPreBuffering)
     2528    {
     2529        LogRel2(("Audio: Warning: Pre-buffering size (%RU32 frames) of stream '%s' does not match buffer size (%RU32 frames), "
     2530                 "setting pre-buffering size to %RU32 frames\n",
     2531                 CfgHostAcq.Backend.cFramesPreBuffering, pStream->szName, CfgHostAcq.Backend.cFramesBufferSize, CfgHostAcq.Backend.cFramesBufferSize));
     2532        CfgHostAcq.Backend.cFramesPreBuffering = CfgHostAcq.Backend.cFramesBufferSize;
     2533    }
     2534
     2535    if (CfgHostAcq.Backend.cFramesPeriod > CfgHostAcq.Backend.cFramesBufferSize)
     2536    {
     2537        LogRel2(("Audio: Warning: Period size (%RU32 frames) of stream '%s' does not match buffer size (%RU32 frames), setting to %RU32 frames\n",
     2538                 CfgHostAcq.Backend.cFramesPeriod, pStream->szName, CfgHostAcq.Backend.cFramesBufferSize, CfgHostAcq.Backend.cFramesBufferSize));
     2539        CfgHostAcq.Backend.cFramesPeriod = CfgHostAcq.Backend.cFramesBufferSize;
     2540    }
     2541
     2542    uint64_t msBufferSize = PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize);
     2543    LogRel2(("Audio: Buffer size of stream '%s' is %RU64ms (%RU32 frames)\n",
     2544             pStream->szName, msBufferSize, CfgHostAcq.Backend.cFramesBufferSize));
     2545
     2546    /* If no own pre-buffer is set, let the backend choose. */
     2547    uint64_t msPreBuf = PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering);
     2548    LogRel2(("Audio: Pre-buffering size of stream '%s' is %RU64ms (%RU32 frames)\n",
     2549             pStream->szName, msPreBuf, CfgHostAcq.Backend.cFramesPreBuffering));
     2550
     2551    /* Make sure the configured buffer size by the backend at least can hold the configured latency. */
     2552    const uint32_t msPeriod = PDMAudioPropsFramesToMilli(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPeriod);
     2553
     2554    LogRel2(("Audio: Period size of stream '%s' is %RU64ms (%RU32 frames)\n",
     2555             pStream->szName, msPeriod, CfgHostAcq.Backend.cFramesPeriod));
     2556
     2557    if (   pCfgGuest->Device.cMsSchedulingHint             /* Any scheduling hint set? */
     2558        && pCfgGuest->Device.cMsSchedulingHint > msPeriod) /* This might lead to buffer underflows. */
     2559    {
     2560        LogRel(("Audio: Warning: Scheduling hint of stream '%s' is bigger (%RU64ms) than used period size (%RU64ms)\n",
     2561                pStream->szName, pCfgGuest->Device.cMsSchedulingHint, msPeriod));
     2562    }
     2563
     2564    /* Destroy any former mixing buffer. */
     2565    AudioMixBufDestroy(&pStream->Host.MixBuf);
     2566
     2567    rc = AudioMixBufInit(&pStream->Host.MixBuf, pStream->szName, &CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize);
     2568    AssertRC(rc);
     2569
     2570    /* Make a copy of the acquired host stream configuration. */
     2571    rc = PDMAudioStrmCfgCopy(&pStream->Host.Cfg, &CfgHostAcq);
     2572    AssertRC(rc);
     2573
     2574    /*
     2575     * Init guest stream.
     2576     */
     2577
     2578    if (pCfgGuest->Device.cMsSchedulingHint)
     2579        LogRel2(("Audio: Stream '%s' got a scheduling hint of %RU32ms (%RU32 bytes)\n",
     2580                 pStream->szName, pCfgGuest->Device.cMsSchedulingHint,
     2581                 PDMAudioPropsMilliToBytes(&pCfgGuest->Props, pCfgGuest->Device.cMsSchedulingHint)));
     2582
     2583    /* Destroy any former mixing buffer. */
     2584    AudioMixBufDestroy(&pStream->Guest.MixBuf);
     2585
     2586    /* Set the guests's default audio data layout. */
     2587    pCfgGuest->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
     2588
     2589    rc = AudioMixBufInit(&pStream->Guest.MixBuf, pStream->szName, &pCfgGuest->Props, CfgHostAcq.Backend.cFramesBufferSize);
     2590    AssertRC(rc);
     2591
     2592    /* Make a copy of the guest stream configuration. */
     2593    rc = PDMAudioStrmCfgCopy(&pStream->Guest.Cfg, pCfgGuest);
     2594    AssertRC(rc);
     2595
     2596    if (RT_FAILURE(rc))
     2597        LogRel(("Audio: Creating stream '%s' failed with %Rrc\n", pStream->szName, rc));
     2598
     2599    if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
     2600    {
     2601        /* Host (Parent) -> Guest (Child). */
     2602        rc = AudioMixBufLinkTo(&pStream->Host.MixBuf, &pStream->Guest.MixBuf);
     2603        AssertRC(rc);
     2604    }
     2605    else
     2606    {
     2607        /* Guest (Parent) -> Host (Child). */
     2608        rc = AudioMixBufLinkTo(&pStream->Guest.MixBuf, &pStream->Host.MixBuf);
     2609        AssertRC(rc);
     2610    }
     2611
     2612    /*
     2613     * Register statistics.
     2614     */
     2615#ifdef VBOX_WITH_STATISTICS
     2616    char szStatName[255];
     2617    if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
     2618    {
     2619        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesCaptured", pStream->szName);
     2620        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalFramesCaptured,
     2621                                  szStatName, STAMUNIT_COUNT, "Total frames played.");
     2622        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesCaptured", pStream->szName);
     2623        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalTimesCaptured,
     2624                                  szStatName, STAMUNIT_COUNT, "Total number of playbacks.");
     2625        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesRead", pStream->szName);
     2626        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalFramesRead,
     2627                                  szStatName, STAMUNIT_COUNT, "Total frames read.");
     2628        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesRead", pStream->szName);
     2629        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->In.Stats.TotalTimesRead,
     2630                                  szStatName, STAMUNIT_COUNT, "Total number of reads.");
     2631    }
     2632    else
     2633    {
     2634        Assert(pCfgGuest->enmDir == PDMAUDIODIR_OUT);
     2635        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesPlayed", pStream->szName);
     2636        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalFramesPlayed,
     2637                                  szStatName, STAMUNIT_COUNT, "Total frames played.");
     2638
     2639        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesPlayed", pStream->szName);
     2640        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalTimesPlayed,
     2641                                  szStatName, STAMUNIT_COUNT, "Total number of playbacks.");
     2642        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalFramesWritten", pStream->szName);
     2643        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalFramesWritten,
     2644                                  szStatName, STAMUNIT_COUNT, "Total frames written.");
     2645
     2646        RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/TotalTimesWritten", pStream->szName);
     2647        PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pStream->Out.Stats.TotalTimesWritten,
     2648                                  szStatName, STAMUNIT_COUNT, "Total number of writes.");
     2649    }
     2650#endif /* VBOX_WITH_STATISTICS */
     2651
     2652    LogFlowFunc(("[%s] Returning %Rrc\n", pStream->szName, rc));
     2653    return rc;
     2654}
     2655
     2656/**
    24122657 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamCreate}
    24132658 */
     
    24172662    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);
    24182663    AssertPtr(pThis);
     2664
     2665    /*
     2666     * Assert sanity.
     2667     */
    24192668    AssertPtrReturn(pCfgHost,   VERR_INVALID_POINTER);
    24202669    AssertPtrReturn(pCfgGuest,  VERR_INVALID_POINTER);
    24212670    AssertPtrReturn(ppStream,   VERR_INVALID_POINTER);
    2422 
    24232671    LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));
    24242672#ifdef LOG_ENABLED
     
    24262674    PDMAudioStrmCfgLog(pCfgGuest);
    24272675#endif
    2428 
     2676    AssertReturn(AudioHlpStreamCfgIsValid(pCfgHost), VERR_INVALID_PARAMETER);
     2677    AssertReturn(AudioHlpStreamCfgIsValid(pCfgGuest), VERR_INVALID_PARAMETER);
     2678    AssertReturn(pCfgHost->enmDir == pCfgGuest->enmDir, VERR_MISMATCH);
     2679    AssertReturn(pCfgHost->enmDir == PDMAUDIODIR_IN || pCfgHost->enmDir == PDMAUDIODIR_OUT, VERR_NOT_SUPPORTED);
     2680
     2681    /*
     2682     * Lock the whole driver instance.
     2683     */
    24292684    int rc = RTCritSectEnter(&pThis->CritSect);
    24302685    AssertRCReturn(rc, rc);
    24312686
    2432     PPDMAUDIOSTREAM pStream = NULL;
    2433 
    2434 #define RC_BREAK(x) { rc = x; break; }
    2435 
    2436     do /* this is not a loop, just a construct to make the code more difficult to follow. */
    2437     {
    2438         if (   !AudioHlpStreamCfgIsValid(pCfgHost)
    2439             || !AudioHlpStreamCfgIsValid(pCfgGuest))
    2440         {
    2441             RC_BREAK(VERR_INVALID_PARAMETER);
    2442         }
    2443 
    2444         /* Make sure that both configurations actually intend the same thing. */
    2445         if (pCfgHost->enmDir != pCfgGuest->enmDir)
    2446         {
    2447             AssertMsgFailed(("Stream configuration directions do not match\n"));
    2448             RC_BREAK(VERR_INVALID_PARAMETER);
    2449         }
    2450 
    2451         /* Note: cbHstStrm will contain the size of the data the backend needs to operate on. */
    2452         size_t cbHstStrm;
    2453         if (pCfgHost->enmDir == PDMAUDIODIR_IN)
    2454         {
    2455             if (!pThis->In.cStreamsFree)
    2456             {
    2457                 LogFlowFunc(("Maximum number of host input streams reached\n"));
    2458                 RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS);
    2459             }
    2460 
    2461             cbHstStrm = pThis->BackendCfg.cbStreamIn;
    2462         }
    2463         else /* Out */
    2464         {
    2465             if (!pThis->Out.cStreamsFree)
    2466             {
    2467                 LogFlowFunc(("Maximum number of host output streams reached\n"));
    2468                 RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);
    2469             }
    2470 
    2471             cbHstStrm = pThis->BackendCfg.cbStreamOut;
    2472         }
    2473         AssertBreakStmt(cbHstStrm < _16M, rc = VERR_OUT_OF_RANGE);
    2474 
     2687    /*
     2688     * Check that we have free streams in the backend and get the
     2689     * size of the backend specific stream data.
     2690     */
     2691    uint32_t *pcFreeStreams;
     2692    size_t    cbHstStrm;
     2693    if (pCfgHost->enmDir == PDMAUDIODIR_IN)
     2694    {
     2695        if (!pThis->In.cStreamsFree)
     2696        {
     2697            LogFlowFunc(("Maximum number of host input streams reached\n"));
     2698            rc = VERR_AUDIO_NO_FREE_INPUT_STREAMS;
     2699        }
     2700        pcFreeStreams = &pThis->In.cStreamsFree;
     2701        cbHstStrm     = pThis->BackendCfg.cbStreamIn;
     2702    }
     2703    else /* Out */
     2704    {
     2705        if (!pThis->Out.cStreamsFree)
     2706        {
     2707            LogFlowFunc(("Maximum number of host output streams reached\n"));
     2708            rc = VERR_AUDIO_NO_FREE_OUTPUT_STREAMS;
     2709        }
     2710        pcFreeStreams = &pThis->Out.cStreamsFree;
     2711        cbHstStrm     = pThis->BackendCfg.cbStreamOut;
     2712    }
     2713    AssertStmt(cbHstStrm < _16M, rc = VERR_OUT_OF_RANGE);
     2714    if (RT_SUCCESS(rc))
     2715    {
    24752716        /*
    24762717         * Allocate and initialize common state.
    24772718         */
    2478         pStream = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM) + RT_ALIGN_Z(cbHstStrm, 64));
    2479         AssertPtrBreakStmt(pStream, rc = VERR_NO_MEMORY);
    2480 
    2481         /* Retrieve host driver name for easier identification. */
    2482         AssertPtr(pThis->pHostDrvAudio);
    2483         PPDMDRVINS pDrvAudioInst = PDMIBASE_2_PDMDRV(pThis->pDrvIns->pDownBase);
    2484         AssertPtr(pDrvAudioInst);
    2485         AssertPtr(pDrvAudioInst->pReg);
    2486 
    2487         Assert(pDrvAudioInst->pReg->szName[0] != '\0');
    2488         RTStrPrintf(pStream->szName, RT_ELEMENTS(pStream->szName), "[%s] %s",
    2489                     pDrvAudioInst->pReg->szName[0] != '\0' ? pDrvAudioInst->pReg->szName : "Untitled",
    2490                     pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>");
    2491 
    2492         pStream->enmDir    = pCfgHost->enmDir;
    2493         pStream->cbBackend = (uint32_t)cbHstStrm;
    2494         if (cbHstStrm)
    2495             pStream->pvBackend = pStream + 1;
    2496 
    2497         /*
    2498          * Try to init the rest.
    2499          */
    2500         rc = drvAudioStreamInitInternal(pThis, pStream, pCfgHost, pCfgGuest);
    2501 
    2502     } while (0);
    2503 
    2504 #undef RC_BREAK
    2505 
    2506     if (RT_FAILURE(rc))
    2507     {
    2508         Log(("drvAudioStreamCreate: failed - %Rrc\n", rc));
     2719        PPDMAUDIOSTREAM pStream = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM) + RT_ALIGN_Z(cbHstStrm, 64));
    25092720        if (pStream)
    25102721        {
    2511             int rc2 = drvAudioStreamUninitInternal(pThis, pStream);
    2512             if (RT_SUCCESS(rc2))
     2722            /* Retrieve host driver name for easier identification. */
     2723            AssertPtr(pThis->pHostDrvAudio);
     2724            PPDMDRVINS pDrvAudioInst = PDMIBASE_2_PDMDRV(pThis->pDrvIns->pDownBase);
     2725            RTStrPrintf(pStream->szName, RT_ELEMENTS(pStream->szName), "[%s] %s",
     2726                        pDrvAudioInst && pDrvAudioInst->pReg && pDrvAudioInst->pReg->szName[0]
     2727                        ? pDrvAudioInst->pReg->szName : "none",
     2728                        pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>");
     2729
     2730            pStream->enmDir    = pCfgHost->enmDir;
     2731            pStream->cbBackend = (uint32_t)cbHstStrm;
     2732            if (cbHstStrm)
     2733                pStream->pvBackend = pStream + 1;
     2734
     2735            /*
     2736             * Try to init the rest.
     2737             */
     2738            rc = drvAudioStreamInitInternal(pThis, pStream, pCfgHost, pCfgGuest);
     2739            if (RT_SUCCESS(rc))
    25132740            {
    2514                 drvAudioStreamFree(pStream);
    2515                 pStream = NULL;
    2516             }
    2517         }
    2518     }
    2519     else
    2520     {
    2521         /* Append the stream to our stream list. */
    2522         RTListAppend(&pThis->lstStreams, &pStream->ListEntry);
    2523 
    2524         /* Set initial reference counts. */
    2525         pStream->cRefs = 1;
    2526 
    2527         char szFile[RTPATH_MAX];
    2528         if (pCfgHost->enmDir == PDMAUDIODIR_IN)
    2529         {
    2530             if (pThis->In.Cfg.Dbg.fEnabled)
    2531             {
    2532                 int rc2 = AudioHlpFileNameGet(szFile, sizeof(szFile), pThis->In.Cfg.Dbg.szPathOut, "DrvAudioCapNonInt",
    2533                                               pThis->pDrvIns->iInstance, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
    2534                 if (RT_SUCCESS(rc2))
     2741                /* Set initial reference counts. */
     2742                pStream->cRefs = 1;
     2743
     2744                /* Decrement the free stream counter. */
     2745                Assert(*pcFreeStreams > 0);
     2746                *pcFreeStreams -= 1;
     2747
     2748                /*
     2749                 * We're good.
     2750                 */
     2751                RTListAppend(&pThis->lstStreams, &pStream->ListEntry);
     2752                STAM_COUNTER_INC(&pThis->Stats.TotalStreamsCreated);
     2753                *ppStream = pStream;
     2754
     2755                /*
     2756                 * Init debug stuff if enabled (ignore failures).
     2757                 */
     2758                if (pCfgHost->enmDir == PDMAUDIODIR_IN)
    25352759                {
    2536                     rc2 = AudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szFile, PDMAUDIOFILE_FLAGS_NONE,
    2537                                              &pStream->In.Dbg.pFileCaptureNonInterleaved);
    2538                     if (RT_SUCCESS(rc2))
    2539                         rc2 = AudioHlpFileOpen(pStream->In.Dbg.pFileCaptureNonInterleaved, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
    2540                                                &pStream->Host.Cfg.Props);
     2760                    if (pThis->In.Cfg.Dbg.fEnabled)
     2761                    {
     2762                        AudioHlpFileCreateAndOpen(&pStream->In.Dbg.pFileCaptureNonInterleaved, pThis->In.Cfg.Dbg.szPathOut,
     2763                                                  "DrvAudioCapNonInt", pThis->pDrvIns->iInstance, &pStream->Host.Cfg.Props);
     2764                        AudioHlpFileCreateAndOpen(&pStream->In.Dbg.pFileStreamRead, pThis->In.Cfg.Dbg.szPathOut,
     2765                                                  "DrvAudioRead", pThis->pDrvIns->iInstance, &pStream->Host.Cfg.Props);
     2766                    }
    25412767                }
    2542 
    2543                 if (RT_SUCCESS(rc2))
     2768                else /* Out */
    25442769                {
    2545                     rc2 = AudioHlpFileNameGet(szFile, sizeof(szFile), pThis->In.Cfg.Dbg.szPathOut, "DrvAudioRead",
    2546                                               pThis->pDrvIns->iInstance, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
    2547                     if (RT_SUCCESS(rc2))
     2770                    if (pThis->Out.Cfg.Dbg.fEnabled)
    25482771                    {
    2549                         rc2 = AudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szFile, PDMAUDIOFILE_FLAGS_NONE,
    2550                                                  &pStream->In.Dbg.pFileStreamRead);
    2551                         if (RT_SUCCESS(rc2))
    2552                             rc2 = AudioHlpFileOpen(pStream->In.Dbg.pFileStreamRead, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
    2553                                                    &pStream->Host.Cfg.Props);
     2772                        AudioHlpFileCreateAndOpen(&pStream->Out.Dbg.pFilePlayNonInterleaved, pThis->Out.Cfg.Dbg.szPathOut,
     2773                                                  "DrvAudioPlayNonInt", pThis->pDrvIns->iInstance, &pStream->Host.Cfg.Props);
     2774                        AudioHlpFileCreateAndOpen(&pStream->Out.Dbg.pFileStreamWrite, pThis->Out.Cfg.Dbg.szPathOut,
     2775                                                  "DrvAudioWrite", pThis->pDrvIns->iInstance, &pStream->Host.Cfg.Props);
    25542776                    }
    25552777                }
    25562778            }
    2557 
    2558             if (pThis->In.cStreamsFree)
    2559                 pThis->In.cStreamsFree--;
    2560         }
    2561         else /* Out */
    2562         {
    2563             if (pThis->Out.Cfg.Dbg.fEnabled)
     2779            else
    25642780            {
    2565                 int rc2 = AudioHlpFileNameGet(szFile, sizeof(szFile), pThis->Out.Cfg.Dbg.szPathOut, "DrvAudioPlayNonInt",
    2566                                               pThis->pDrvIns->iInstance, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
    2567                 if (RT_SUCCESS(rc2))
    2568                 {
    2569                     rc2 = AudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szFile, PDMAUDIOFILE_FLAGS_NONE,
    2570                                              &pStream->Out.Dbg.pFilePlayNonInterleaved);
    2571                     if (RT_SUCCESS(rc2))
    2572                         rc = AudioHlpFileOpen(pStream->Out.Dbg.pFilePlayNonInterleaved, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
    2573                                               &pStream->Host.Cfg.Props);
    2574                 }
    2575 
    2576                 if (RT_SUCCESS(rc2))
    2577                 {
    2578                     rc2 = AudioHlpFileNameGet(szFile, sizeof(szFile), pThis->Out.Cfg.Dbg.szPathOut, "DrvAudioWrite",
    2579                                               pThis->pDrvIns->iInstance, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
    2580                     if (RT_SUCCESS(rc2))
    2581                     {
    2582                         rc2 = AudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szFile, PDMAUDIOFILE_FLAGS_NONE,
    2583                                                  &pStream->Out.Dbg.pFileStreamWrite);
    2584                         if (RT_SUCCESS(rc2))
    2585                             rc2 = AudioHlpFileOpen(pStream->Out.Dbg.pFileStreamWrite, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
    2586                                                    &pStream->Host.Cfg.Props);
    2587                     }
    2588                 }
     2781                LogFunc(("drvAudioStreamInitInternal failed: %Rrc\n", rc));
     2782                int rc2 = drvAudioStreamUninitInternal(pThis, pStream);
     2783                AssertRC(rc2);
     2784                drvAudioStreamFree(pStream);
    25892785            }
    2590 
    2591             if (pThis->Out.cStreamsFree)
    2592                 pThis->Out.cStreamsFree--;
    2593         }
    2594 
    2595 #ifdef VBOX_WITH_STATISTICS
    2596         STAM_COUNTER_ADD(&pThis->Stats.TotalStreamsCreated, 1);
    2597 #endif
    2598         *ppStream = pStream;
     2786        }
     2787        else
     2788            rc = VERR_NO_MEMORY;
    25992789    }
    26002790
     
    29423132    LogFlowFuncLeaveRC(rc);
    29433133    return rc;
    2944 }
    2945 
    2946 /**
    2947  * Creates an audio stream on the backend side.
    2948  *
    2949  * @returns IPRT status code.
    2950  * @param   pThis               Pointer to driver instance.
    2951  * @param   pStream             Audio stream to create the backend side for.
    2952  * @param   pCfgReq             Requested audio stream configuration to use for stream creation.
    2953  * @param   pCfgAcq             Acquired audio stream configuration returned by the backend.
    2954  *
    2955  * @note    Configuration precedence for requested audio stream configuration (first has highest priority, if set):
    2956  *          - per global extra-data
    2957  *          - per-VM extra-data
    2958  *          - requested configuration (by pCfgReq)
    2959  *          - default value
    2960  */
    2961 static int drvAudioStreamCreateInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream,
    2962                                                PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    2963 {
    2964     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    2965     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    2966     AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
    2967     AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
    2968 
    2969     AssertMsg((pStream->fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED) == 0,
    2970               ("Stream '%s' already initialized in backend\n", pStream->szName));
    2971 
    2972     /* Get the right configuration for the stream to be created. */
    2973     PDRVAUDIOCFG pDrvCfg = pCfgReq->enmDir == PDMAUDIODIR_IN ? &pThis->In.Cfg : &pThis->Out.Cfg;
    2974 
    2975     /* Fill in the tweakable parameters into the requested host configuration.
    2976      * All parameters in principle can be changed and returned by the backend via the acquired configuration. */
    2977 
    2978     /*
    2979      * PCM
    2980      */
    2981     if (PDMAudioPropsSampleSize(&pDrvCfg->Props) != 0) /* Anything set via custom extra-data? */
    2982     {
    2983         PDMAudioPropsSetSampleSize(&pCfgReq->Props, PDMAudioPropsSampleSize(&pDrvCfg->Props));
    2984         LogRel2(("Audio: Using custom sample size of %RU8 bytes for stream '%s'\n",
    2985                  PDMAudioPropsSampleSize(&pCfgReq->Props), pStream->szName));
    2986     }
    2987 
    2988     if (pDrvCfg->Props.uHz) /* Anything set via custom extra-data? */
    2989     {
    2990         pCfgReq->Props.uHz = pDrvCfg->Props.uHz;
    2991         LogRel2(("Audio: Using custom Hz rate %RU32 for stream '%s'\n", pCfgReq->Props.uHz, pStream->szName));
    2992     }
    2993 
    2994     if (pDrvCfg->uSigned != UINT8_MAX) /* Anything set via custom extra-data? */
    2995     {
    2996         pCfgReq->Props.fSigned = RT_BOOL(pDrvCfg->uSigned);
    2997         LogRel2(("Audio: Using custom %s sample format for stream '%s'\n",
    2998                  pCfgReq->Props.fSigned ? "signed" : "unsigned", pStream->szName));
    2999     }
    3000 
    3001     if (pDrvCfg->uSwapEndian != UINT8_MAX) /* Anything set via custom extra-data? */
    3002     {
    3003         pCfgReq->Props.fSwapEndian = RT_BOOL(pDrvCfg->uSwapEndian);
    3004         LogRel2(("Audio: Using custom %s endianess for samples of stream '%s'\n",
    3005                  pCfgReq->Props.fSwapEndian ? "swapped" : "original", pStream->szName));
    3006     }
    3007 
    3008     if (PDMAudioPropsChannels(&pDrvCfg->Props) != 0) /* Anything set via custom extra-data? */
    3009     {
    3010         PDMAudioPropsSetChannels(&pCfgReq->Props, PDMAudioPropsChannels(&pDrvCfg->Props));
    3011         LogRel2(("Audio: Using custom %RU8 channel(s) for stream '%s'\n", PDMAudioPropsChannels(&pDrvCfg->Props), pStream->szName));
    3012     }
    3013 
    3014     /* Validate PCM properties. */
    3015     if (!AudioHlpPcmPropsAreValid(&pCfgReq->Props))
    3016     {
    3017         LogRel(("Audio: Invalid custom PCM properties set for stream '%s', cannot create stream\n", pStream->szName));
    3018         return VERR_INVALID_PARAMETER;
    3019     }
    3020 
    3021     /*
    3022      * Period size
    3023      */
    3024     const char *pszWhat = "device-specific";
    3025     if (pDrvCfg->uPeriodSizeMs)
    3026     {
    3027         pCfgReq->Backend.cFramesPeriod = PDMAudioPropsMilliToFrames(&pCfgReq->Props, pDrvCfg->uPeriodSizeMs);
    3028         pszWhat = "custom";
    3029     }
    3030 
    3031     if (!pCfgReq->Backend.cFramesPeriod) /* Set default period size if nothing explicitly is set. */
    3032     {
    3033         pCfgReq->Backend.cFramesPeriod = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 150 /*ms*/);
    3034         pszWhat = "default";
    3035     }
    3036 
    3037     LogRel2(("Audio: Using %s period size %RU64 ms / %RU32 frames for stream '%s'\n",
    3038              pszWhat, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod),
    3039              pCfgReq->Backend.cFramesPeriod, pStream->szName));
    3040 
    3041     /*
    3042      * Buffer size
    3043      */
    3044     pszWhat = "device-specific";
    3045     if (pDrvCfg->uBufferSizeMs)
    3046     {
    3047         pCfgReq->Backend.cFramesBufferSize = PDMAudioPropsMilliToFrames(&pCfgReq->Props, pDrvCfg->uBufferSizeMs);
    3048         pszWhat = "custom";
    3049     }
    3050 
    3051     if (!pCfgReq->Backend.cFramesBufferSize) /* Set default buffer size if nothing explicitly is set. */
    3052     {
    3053         pCfgReq->Backend.cFramesBufferSize = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 300 /*ms*/);
    3054         pszWhat = "default";
    3055     }
    3056 
    3057     LogRel2(("Audio: Using %s buffer size %RU64 ms / %RU32 frames for stream '%s'\n",
    3058              pszWhat, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize),
    3059              pCfgReq->Backend.cFramesBufferSize, pStream->szName));
    3060 
    3061     /*
    3062      * Pre-buffering size
    3063      */
    3064     pszWhat = "device-specific";
    3065     if (pDrvCfg->uPreBufSizeMs != UINT32_MAX) /* Anything set via global / per-VM extra-data? */
    3066     {
    3067         pCfgReq->Backend.cFramesPreBuffering = PDMAudioPropsMilliToFrames(&pCfgReq->Props, pDrvCfg->uPreBufSizeMs);
    3068         pszWhat = "custom";
    3069     }
    3070     else /* No, then either use the default or device-specific settings (if any). */
    3071     {
    3072         if (pCfgReq->Backend.cFramesPreBuffering == UINT32_MAX) /* Set default pre-buffering size if nothing explicitly is set. */
    3073         {
    3074             /* For pre-buffering to finish the buffer at least must be full one time. */
    3075             pCfgReq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesBufferSize;
    3076             pszWhat = "default";
    3077         }
    3078     }
    3079 
    3080     LogRel2(("Audio: Using %s pre-buffering size %RU64 ms / %RU32 frames for stream '%s'\n",
    3081              pszWhat, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPreBuffering),
    3082              pCfgReq->Backend.cFramesPreBuffering, pStream->szName));
    3083 
    3084     /*
    3085      * Validate input.
    3086      */
    3087     if (pCfgReq->Backend.cFramesBufferSize < pCfgReq->Backend.cFramesPeriod)
    3088     {
    3089         LogRel(("Audio: Error for stream '%s': Buffering size (%RU64ms) must not be smaller than the period size (%RU64ms)\n",
    3090                 pStream->szName, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize),
    3091                 PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod)));
    3092         return VERR_INVALID_PARAMETER;
    3093     }
    3094 
    3095     if (   pCfgReq->Backend.cFramesPreBuffering != UINT32_MAX /* Custom pre-buffering set? */
    3096         && pCfgReq->Backend.cFramesPreBuffering)
    3097     {
    3098         if (pCfgReq->Backend.cFramesBufferSize < pCfgReq->Backend.cFramesPreBuffering)
    3099         {
    3100             LogRel(("Audio: Error for stream '%s': Buffering size (%RU64ms) must not be smaller than the pre-buffering size (%RU64ms)\n",
    3101                     pStream->szName, PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesPreBuffering),
    3102                     PDMAudioPropsFramesToMilli(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize)));
    3103             return VERR_INVALID_PARAMETER;
    3104         }
    3105     }
    3106 
    3107     /* Make the acquired host configuration the requested host configuration initially,
    3108      * in case the backend does not report back an acquired configuration. */
    3109     int rc = PDMAudioStrmCfgCopy(pCfgAcq, pCfgReq);
    3110     if (RT_FAILURE(rc))
    3111     {
    3112         LogRel(("Audio: Creating stream '%s' with an invalid backend configuration not possible, skipping\n",
    3113                 pStream->szName));
    3114         return rc;
    3115     }
    3116 
    3117     rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStream->pvBackend, pCfgReq, pCfgAcq);
    3118     if (RT_FAILURE(rc))
    3119     {
    3120         if (rc == VERR_NOT_SUPPORTED)
    3121             LogRel2(("Audio: Creating stream '%s' in backend not supported\n", pStream->szName));
    3122         else if (rc == VERR_AUDIO_STREAM_COULD_NOT_CREATE)
    3123             LogRel2(("Audio: Stream '%s' could not be created in backend because of missing hardware / drivers\n", pStream->szName));
    3124         else
    3125             LogRel(("Audio: Creating stream '%s' in backend failed with %Rrc\n", pStream->szName, rc));
    3126 
    3127         return rc;
    3128     }
    3129 
    3130     /* Validate acquired configuration. */
    3131     char szTmp[PDMAUDIOPROPSTOSTRING_MAX];
    3132     AssertLogRelMsgReturn(AudioHlpStreamCfgIsValid(pCfgAcq),
    3133                           ("Audio: Creating stream '%s' returned an invalid backend configuration (%s), skipping\n",
    3134                            pStream->szName, PDMAudioPropsToString(&pCfgAcq->Props, szTmp, sizeof(szTmp))),
    3135                           VERR_INVALID_PARAMETER);
    3136 
    3137     /* Let the user know that the backend changed one of the values requested above. */
    3138     if (pCfgAcq->Backend.cFramesBufferSize != pCfgReq->Backend.cFramesBufferSize)
    3139         LogRel2(("Audio: Buffer size overwritten by backend for stream '%s' (now %RU64ms, %RU32 frames)\n",
    3140                  pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesBufferSize), pCfgAcq->Backend.cFramesBufferSize));
    3141 
    3142     if (pCfgAcq->Backend.cFramesPeriod != pCfgReq->Backend.cFramesPeriod)
    3143         LogRel2(("Audio: Period size overwritten by backend for stream '%s' (now %RU64ms, %RU32 frames)\n",
    3144                  pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesPeriod), pCfgAcq->Backend.cFramesPeriod));
    3145 
    3146     /* Was pre-buffering requested, but the acquired configuration from the backend told us something else? */
    3147     if (pCfgReq->Backend.cFramesPreBuffering)
    3148     {
    3149         if (pCfgAcq->Backend.cFramesPreBuffering != pCfgReq->Backend.cFramesPreBuffering)
    3150             LogRel2(("Audio: Pre-buffering size overwritten by backend for stream '%s' (now %RU64ms, %RU32 frames)\n",
    3151                      pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesPreBuffering), pCfgAcq->Backend.cFramesPreBuffering));
    3152 
    3153         if (pCfgAcq->Backend.cFramesPreBuffering > pCfgAcq->Backend.cFramesBufferSize)
    3154         {
    3155             pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesBufferSize;
    3156             LogRel2(("Audio: Pre-buffering size bigger than buffer size for stream '%s', adjusting to %RU64ms (%RU32 frames)\n",
    3157                      pStream->szName, PDMAudioPropsFramesToMilli(&pCfgAcq->Props, pCfgAcq->Backend.cFramesPreBuffering), pCfgAcq->Backend.cFramesPreBuffering));
    3158         }
    3159     }
    3160     else if (pCfgReq->Backend.cFramesPreBuffering == 0) /* Was the pre-buffering requested as being disabeld? Tell the users. */
    3161     {
    3162         LogRel2(("Audio: Pre-buffering is disabled for stream '%s'\n", pStream->szName));
    3163         pCfgAcq->Backend.cFramesPreBuffering = 0;
    3164     }
    3165 
    3166     /* Sanity for detecting buggy backends. */
    3167     AssertMsgReturn(pCfgAcq->Backend.cFramesPeriod < pCfgAcq->Backend.cFramesBufferSize,
    3168                     ("Acquired period size must be smaller than buffer size\n"),
    3169                     VERR_INVALID_PARAMETER);
    3170     AssertMsgReturn(pCfgAcq->Backend.cFramesPreBuffering <= pCfgAcq->Backend.cFramesBufferSize,
    3171                     ("Acquired pre-buffering size must be smaller or as big as the buffer size\n"),
    3172                     VERR_INVALID_PARAMETER);
    3173 
    3174     pStream->fStatus |= PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED;
    3175 
    3176     return VINF_SUCCESS;
    31773134}
    31783135
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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