儲存庫 vbox 的更動 88292
- 時間撮記:
- 2021-3-25 下午01:17:32 (4 年 以前)
- svn:sync-xref-src-repo-rev:
- 143503
- 位置:
- trunk/src/VBox/Devices/Audio
- 檔案:
-
- 修改 3 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/Devices/Audio/AudioHlp.cpp
r88269 r88292 586 586 587 587 /** 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 */ 601 int 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 */ 636 int 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 /** 588 646 * Closes an audio file. 589 647 * -
trunk/src/VBox/Devices/Audio/AudioHlp.h
r88235 r88292 62 62 /** @name Audio file methods. 63 63 * @{ */ 64 int AudioHlpFileCreateAndOpen(PPDMAUDIOFILE *ppFile, const char *pszDir, const char *pszName, 65 uint32_t iInstance, PCPDMAUDIOPCMPROPS pProps); 66 int 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); 64 69 int AudioHlpFileCreate(PDMAUDIOFILETYPE enmType, const char *pszFile, uint32_t fFlags, PPDMAUDIOFILE *ppFile); 65 70 void AudioHlpFileDestroy(PPDMAUDIOFILE pFile); -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88278 r88292 686 686 687 687 /** 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_ENABLED713 LogFunc(("[%s] Requested host format:\n", pStream->szName));714 PDMAudioStrmCfgLog(pCfgHost);715 #endif716 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 else841 {842 /* Guest (Parent) -> Host (Child). */843 rc = AudioMixBufLinkTo(&pStream->Guest.MixBuf, &pStream->Host.MixBuf);844 AssertRC(rc);845 }846 847 #ifdef VBOX_WITH_STATISTICS848 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 else883 AssertFailed();884 #endif885 886 LogFlowFunc(("[%s] Returning %Rrc\n", pStream->szName, rc));887 return rc;888 }889 890 /**891 688 * Frees an audio stream and its allocated resources. 892 689 * … … 2410 2207 2411 2208 /** 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 */ 2224 static 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 */ 2461 static 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 /** 2412 2657 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamCreate} 2413 2658 */ … … 2417 2662 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 2418 2663 AssertPtr(pThis); 2664 2665 /* 2666 * Assert sanity. 2667 */ 2419 2668 AssertPtrReturn(pCfgHost, VERR_INVALID_POINTER); 2420 2669 AssertPtrReturn(pCfgGuest, VERR_INVALID_POINTER); 2421 2670 AssertPtrReturn(ppStream, VERR_INVALID_POINTER); 2422 2423 2671 LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName)); 2424 2672 #ifdef LOG_ENABLED … … 2426 2674 PDMAudioStrmCfgLog(pCfgGuest); 2427 2675 #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 */ 2429 2684 int rc = RTCritSectEnter(&pThis->CritSect); 2430 2685 AssertRCReturn(rc, rc); 2431 2686 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 { 2475 2716 /* 2476 2717 * Allocate and initialize common state. 2477 2718 */ 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)); 2509 2720 if (pStream) 2510 2721 { 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)) 2513 2740 { 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) 2535 2759 { 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 } 2541 2767 } 2542 2543 if (RT_SUCCESS(rc2)) 2768 else /* Out */ 2544 2769 { 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) 2548 2771 { 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); 2554 2776 } 2555 2777 } 2556 2778 } 2557 2558 if (pThis->In.cStreamsFree) 2559 pThis->In.cStreamsFree--; 2560 } 2561 else /* Out */ 2562 { 2563 if (pThis->Out.Cfg.Dbg.fEnabled) 2779 else 2564 2780 { 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); 2589 2785 } 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; 2599 2789 } 2600 2790 … … 2942 3132 LogFlowFuncLeaveRC(rc); 2943 3133 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-data2957 * - per-VM extra-data2958 * - requested configuration (by pCfgReq)2959 * - default value2960 */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 * PCM2980 */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 size3023 */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 size3043 */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 size3063 */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 else3125 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;3177 3134 } 3178 3135
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器