Changeset 89329 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- May 28, 2021 12:26:17 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144678
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r89327 r89329 511 511 } 512 512 513 513 #ifdef LOG_ENABLED 514 514 /** 515 515 * Get capture state name string. … … 528 528 return "BAD"; 529 529 } 530 530 #endif 531 531 532 532 /** … … 3862 3862 3863 3863 3864 #ifdef OLD_CAPTURE_CODE3865 /**3866 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRead}3867 */3868 static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,3869 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)3870 {3871 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);3872 AssertPtr(pThis);3873 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream;3874 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER);3875 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);3876 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);3877 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);3878 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);3879 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);3880 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_IN,3881 ("Stream '%s' is not an input stream and therefore cannot be read from (direction is 0x%x)\n",3882 pStreamEx->Core.szName, pStreamEx->Core.enmDir));3883 3884 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect);3885 AssertRCReturn(rc, rc);3886 3887 /*3888 * ...3889 */3890 uint32_t cbReadTotal = 0;3891 3892 do3893 {3894 uint32_t cfReadTotal = 0;3895 3896 const uint32_t cfBuf = AUDIOMIXBUF_B2F(&pStreamEx->Guest.MixBuf, cbBuf);3897 3898 if (pThis->In.fEnabled) /* Input for this audio driver enabled? See #9822. */3899 {3900 if (!PDMAudioStrmStatusCanRead(pStreamEx->fStatus))3901 {3902 rc = VERR_AUDIO_STREAM_NOT_READY;3903 break;3904 }3905 3906 /*3907 * Read from the parent buffer (that is, the guest buffer) which3908 * should have the audio data in the format the guest needs.3909 */3910 uint32_t cfToRead = RT_MIN(cfBuf, AudioMixBufLive(&pStreamEx->Guest.MixBuf));3911 while (cfToRead)3912 {3913 uint32_t cfRead;3914 rc = AudioMixBufAcquireReadBlock(&pStreamEx->Guest.MixBuf,3915 (uint8_t *)pvBuf + AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadTotal),3916 AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfToRead), &cfRead);3917 if (RT_FAILURE(rc))3918 break;3919 3920 #ifdef VBOX_WITH_STATISTICS3921 const uint32_t cbRead = AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfRead);3922 STAM_COUNTER_ADD(&pThis->Stats.TotalBytesRead, cbRead);3923 STAM_COUNTER_ADD(&pStreamEx->In.Stats.TotalFramesRead, cfRead);3924 STAM_COUNTER_INC(&pStreamEx->In.Stats.TotalTimesRead);3925 #endif3926 Assert(cfToRead >= cfRead);3927 cfToRead -= cfRead;3928 3929 cfReadTotal += cfRead;3930 3931 AudioMixBufReleaseReadBlock(&pStreamEx->Guest.MixBuf, cfRead);3932 }3933 3934 if (cfReadTotal)3935 {3936 if (pThis->CfgIn.Dbg.fEnabled)3937 AudioHlpFileWrite(pStreamEx->In.Dbg.pFileStreamRead,3938 pvBuf, AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadTotal), 0 /* fFlags */);3939 3940 AudioMixBufFinish(&pStreamEx->Guest.MixBuf, cfReadTotal);3941 }3942 }3943 3944 /* If we were not able to read as much data as requested, fill up the returned3945 * data with silence.3946 *3947 * This is needed to keep the device emulation DMA transfers up and running at a constant rate. */3948 if (cfReadTotal < cfBuf)3949 {3950 Log3Func(("[%s] Filling in silence (%RU64ms / %RU64ms)\n", pStream->szName,3951 PDMAudioPropsFramesToMilli(&pStreamEx->Guest.Cfg.Props, cfBuf - cfReadTotal),3952 PDMAudioPropsFramesToMilli(&pStreamEx->Guest.Cfg.Props, cfBuf)));3953 3954 PDMAudioPropsClearBuffer(&pStreamEx->Guest.Cfg.Props,3955 (uint8_t *)pvBuf + AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadTotal),3956 AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfBuf - cfReadTotal),3957 cfBuf - cfReadTotal);3958 3959 cfReadTotal = cfBuf;3960 }3961 3962 cbReadTotal = AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadTotal);3963 3964 pStreamEx->nsLastReadWritten = RTTimeNanoTS();3965 3966 Log3Func(("[%s] fEnabled=%RTbool, cbReadTotal=%RU32, rc=%Rrc\n", pStream->szName, pThis->In.fEnabled, cbReadTotal, rc));3967 3968 } while (0);3969 3970 RTCritSectLeave(&pStreamEx->Core.CritSect);3971 3972 if (RT_SUCCESS(rc) && pcbRead)3973 *pcbRead = cbReadTotal;3974 return rc;3975 }3976 3977 3978 /**3979 * Captures non-interleaved input from a host stream.3980 *3981 * @returns VBox status code.3982 * @param pThis Driver instance.3983 * @param pStreamEx Stream to capture from.3984 * @param pcfCaptured Number of (host) audio frames captured.3985 */3986 static int drvAudioStreamCaptureNonInterleaved(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t *pcfCaptured)3987 {3988 Assert(pStreamEx->Core.enmDir == PDMAUDIODIR_IN);3989 Assert(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED);3990 3991 /*3992 * ...3993 */3994 uint32_t cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend);3995 if (!cbReadable)3996 Log2Func(("[%s] No readable data available\n", pStreamEx->Core.szName));3997 3998 uint32_t cbFree = AudioMixBufFreeBytes(&pStreamEx->Guest.MixBuf); /* Parent */3999 if (!cbFree)4000 Log2Func(("[%s] Buffer full\n", pStreamEx->Core.szName));4001 4002 if (cbReadable > cbFree) /* More data readable than we can store at the moment? Limit. */4003 cbReadable = cbFree;4004 4005 /*4006 * ...4007 */4008 int rc = VINF_SUCCESS;4009 uint32_t cfCapturedTotal = 0;4010 while (cbReadable)4011 {4012 uint8_t abChunk[_4K];4013 uint32_t cbCaptured;4014 rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pStreamEx->pBackend,4015 abChunk, RT_MIN(cbReadable, (uint32_t)sizeof(abChunk)), &cbCaptured);4016 if (RT_FAILURE(rc))4017 {4018 int rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);4019 AssertRC(rc2);4020 break;4021 }4022 4023 Assert(cbCaptured <= sizeof(abChunk));4024 if (cbCaptured > sizeof(abChunk)) /* Paranoia. */4025 cbCaptured = (uint32_t)sizeof(abChunk);4026 4027 if (!cbCaptured) /* Nothing captured? Take a shortcut. */4028 break;4029 4030 /* We use the host side mixing buffer as an intermediate buffer to do some4031 * (first) processing (if needed), so always write the incoming data at offset 0. */4032 uint32_t cfHstWritten = 0;4033 rc = AudioMixBufWriteAt(&pStreamEx->Host.MixBuf, 0 /* offFrames */, abChunk, cbCaptured, &cfHstWritten);4034 if ( RT_FAILURE(rc)4035 || !cfHstWritten)4036 {4037 AssertMsgFailed(("[%s] Write failed: cbCaptured=%RU32, cfHstWritten=%RU32, rc=%Rrc\n",4038 pStreamEx->Core.szName, cbCaptured, cfHstWritten, rc));4039 break;4040 }4041 4042 if (pThis->CfgIn.Dbg.fEnabled)4043 AudioHlpFileWrite(pStreamEx->In.Dbg.pFileCapture, abChunk, cbCaptured, 0 /* fFlags */);4044 4045 uint32_t cfHstMixed = 0;4046 if (cfHstWritten)4047 {4048 int rc2 = AudioMixBufMixToParentEx(&pStreamEx->Host.MixBuf, 0 /* cSrcOffset */, cfHstWritten /* cSrcFrames */,4049 &cfHstMixed /* pcSrcMixed */);4050 Log3Func(("[%s] cbCaptured=%RU32, cfWritten=%RU32, cfMixed=%RU32, rc=%Rrc\n",4051 pStreamEx->Core.szName, cbCaptured, cfHstWritten, cfHstMixed, rc2));4052 AssertRC(rc2);4053 }4054 4055 Assert(cbReadable >= cbCaptured);4056 cbReadable -= cbCaptured;4057 cfCapturedTotal += cfHstMixed;4058 }4059 4060 if (RT_SUCCESS(rc))4061 {4062 if (cfCapturedTotal)4063 Log2Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCapturedTotal, rc));4064 }4065 else4066 LogFunc(("[%s] Capturing failed with rc=%Rrc\n", pStreamEx->Core.szName, rc));4067 4068 if (pcfCaptured)4069 *pcfCaptured = cfCapturedTotal;4070 4071 return rc;4072 }4073 4074 4075 /**4076 * Captures raw input from a host stream.4077 *4078 * Raw input means that the backend directly operates on PDMAUDIOFRAME structs without4079 * no data layout processing done in between.4080 *4081 * Needed for e.g. the VRDP audio backend (in Main).4082 *4083 * @returns VBox status code.4084 * @param pThis Driver instance.4085 * @param pStreamEx Stream to capture from.4086 * @param pcfCaptured Number of (host) audio frames captured.4087 */4088 static int drvAudioStreamCaptureRaw(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t *pcfCaptured)4089 {4090 Assert(pStreamEx->Core.enmDir == PDMAUDIODIR_IN);4091 Assert(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_RAW);4092 AssertPtr(pThis->pHostDrvAudio->pfnStreamGetReadable);4093 4094 /*4095 * ...4096 */4097 /* Note: Raw means *audio frames*, not bytes! */4098 uint32_t cfReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend);4099 if (!cfReadable)4100 Log2Func(("[%s] No readable data available\n", pStreamEx->Core.szName));4101 4102 const uint32_t cfFree = AudioMixBufFree(&pStreamEx->Guest.MixBuf); /* Parent */4103 if (!cfFree)4104 Log2Func(("[%s] Buffer full\n", pStreamEx->Core.szName));4105 4106 if (cfReadable > cfFree) /* More data readable than we can store at the moment? Limit. */4107 cfReadable = cfFree;4108 4109 /*4110 * ...4111 */4112 int rc = VINF_SUCCESS;4113 uint32_t cfCapturedTotal = 0;4114 while (cfReadable)4115 {4116 PPDMAUDIOFRAME paFrames;4117 uint32_t cfWritable;4118 rc = AudioMixBufPeekMutable(&pStreamEx->Host.MixBuf, cfReadable, &paFrames, &cfWritable);4119 if ( RT_FAILURE(rc)4120 || !cfWritable)4121 break;4122 4123 uint32_t cfCaptured;4124 rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pStreamEx->pBackend,4125 paFrames, cfWritable, &cfCaptured);4126 if (RT_FAILURE(rc))4127 {4128 int rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);4129 AssertRC(rc2);4130 break;4131 }4132 4133 Assert(cfCaptured <= cfWritable);4134 if (cfCaptured > cfWritable) /* Paranoia. */4135 cfCaptured = cfWritable;4136 4137 Assert(cfReadable >= cfCaptured);4138 cfReadable -= cfCaptured;4139 cfCapturedTotal += cfCaptured;4140 }4141 4142 if (pcfCaptured)4143 *pcfCaptured = cfCapturedTotal;4144 Log2Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCapturedTotal, rc));4145 return rc;4146 }4147 4148 4149 /**4150 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamCapture}4151 */4152 static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface,4153 PPDMAUDIOSTREAM pStream, uint32_t *pcFramesCaptured)4154 {4155 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);4156 AssertPtr(pThis);4157 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream;4158 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER);4159 AssertPtrNull(pcFramesCaptured);4160 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);4161 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);4162 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_IN,4163 ("Stream '%s' is not an input stream and therefore cannot be captured (direction is 0x%x)\n",4164 pStreamEx->Core.szName, pStreamEx->Core.enmDir));4165 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect);4166 AssertRCReturn(rc, rc);4167 RTCritSectRwEnterShared(&pThis->CritSectHotPlug);4168 4169 #ifdef LOG_ENABLED4170 char szStreamSts[DRVAUDIO_STATUS_STR_MAX];4171 #endif4172 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, drvAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));4173 4174 /*4175 * ...4176 */4177 uint32_t cfCaptured = 0;4178 do4179 {4180 if (!pThis->pHostDrvAudio)4181 {4182 rc = VERR_PDM_NO_ATTACHED_DRIVER;4183 break;4184 }4185 4186 if ( !pThis->In.fEnabled4187 || !PDMAudioStrmStatusCanRead(pStreamEx->fStatus)4188 || !(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY))4189 {4190 rc = VERR_AUDIO_STREAM_NOT_READY;4191 break;4192 }4193 4194 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx);4195 if (enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY)4196 {4197 /*4198 * Do the actual capturing.4199 */4200 if (RT_LIKELY(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED))4201 rc = drvAudioStreamCaptureNonInterleaved(pThis, pStreamEx, &cfCaptured);4202 else if (pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_RAW)4203 rc = drvAudioStreamCaptureRaw(pThis, pStreamEx, &cfCaptured);4204 else4205 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);4206 4207 if (RT_SUCCESS(rc))4208 {4209 Log3Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCaptured, rc));4210 4211 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn, cfCaptured);4212 STAM_COUNTER_ADD(&pStreamEx->In.Stats.TotalFramesCaptured, cfCaptured);4213 }4214 else if (RT_UNLIKELY(RT_FAILURE(rc)))4215 LogRel(("Audio: Capturing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc));4216 }4217 else4218 rc = VERR_AUDIO_STREAM_NOT_READY;4219 } while (0);4220 4221 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug);4222 RTCritSectLeave(&pStreamEx->Core.CritSect);4223 4224 if (pcFramesCaptured)4225 *pcFramesCaptured = cfCaptured;4226 4227 if (RT_FAILURE(rc))4228 LogFlowFuncLeaveRC(rc);4229 return rc;4230 }4231 #endif4232 4233 4234 3864 /********************************************************************************************************************************* 4235 3865 * PDMIHOSTAUDIOPORT interface implementation. *
Note:
See TracChangeset
for help on using the changeset viewer.