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