Changeset 88376 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Apr 6, 2021 8:35:18 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143623
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioDSound.cpp
r88371 r88376 125 125 bool fEnabled; 126 126 bool afPadding[2]; 127 /** Size (in bytes) of the DirectSound buffer. 128 * @note This in *not* the size of the circular buffer above! */ 127 /** Size (in bytes) of the DirectSound buffer. */ 129 128 DWORD cbBufSize; 130 129 /** The stream's critical section for synchronizing access. */ 131 130 RTCRITSECT CritSect; 132 /** The internal playback / capturing buffer. */133 PRTCIRCBUF pCircBuf;134 131 union 135 132 { … … 149 146 * This is a secondary buffer and is used as a streaming buffer. */ 150 147 LPDIRECTSOUNDBUFFER8 pDSB; 151 /** Current write offset (in bytes) within the DSB. */ 148 /** Current write offset (in bytes) within the DSB. 149 * @note This is needed as the current write position as kept by direct sound 150 * will move ahead if we're too late. */ 152 151 DWORD offWritePos; 153 152 /** Offset of last play cursor within the DSB when checked for pending. */ … … 282 281 * Retrieves the number of free bytes available for writing to a DirectSound output stream. 283 282 * 284 * @return IPRT status code. VERR_NOT_AVAILABLE if unable to determine or the buffer was not recoverable. 283 * @return VBox status code. VERR_NOT_AVAILABLE if unable to determine or the 284 * buffer was not recoverable. 285 285 * @param pThis Host audio driver instance. 286 286 * @param pStreamDS DirectSound output stream to retrieve number for. 287 287 * @param pdwFree Where to return the free amount on success. 288 */ 289 static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD *pdwFree) 288 * @param poffPlayCursor Where to return the play cursor offset. 289 */ 290 static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD *pdwFree, DWORD *poffPlayCursor) 290 291 { 291 292 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 292 293 AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER); 293 294 AssertPtrReturn(pdwFree, VERR_INVALID_POINTER); 295 AssertPtr(poffPlayCursor); 294 296 295 297 Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT); /* Paranoia. */ … … 307 309 for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++) 308 310 { 309 DWORD cbPlayCursor, cbWriteCursor; 310 hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayCursor, &cbWriteCursor); 311 DWORD offPlayCursor = 0; 312 DWORD offWriteCursor = 0; 313 hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor); 311 314 if (SUCCEEDED(hr)) 312 315 { 313 int32_t cbDiff = cbWriteCursor - cbPlayCursor;316 int32_t cbDiff = offWriteCursor - offPlayCursor; 314 317 if (cbDiff < 0) 315 318 cbDiff += pStreamDS->cbBufSize; 316 319 317 int32_t cbFree = cbPlayCursor - pStreamDS->Out.offWritePos;320 int32_t cbFree = offPlayCursor - pStreamDS->Out.offWritePos; 318 321 if (cbFree < 0) 319 322 cbFree += pStreamDS->cbBufSize; … … 321 324 if (cbFree > (int32_t)pStreamDS->cbBufSize - cbDiff) 322 325 { 323 pStreamDS->Out.offWritePos = cbWriteCursor; 326 /** @todo count/log these. */ 327 pStreamDS->Out.offWritePos = offWriteCursor; 324 328 cbFree = pStreamDS->cbBufSize - cbDiff; 325 329 } 326 330 327 /* When starting to use a DirectSound buffer, cbPlayCursor and cbWriteCursor331 /* When starting to use a DirectSound buffer, offPlayCursor and offWriteCursor 328 332 * both point at position 0, so we won't be able to detect how many bytes 329 333 * are writable that way. … … 333 337 cbFree = pStreamDS->cbBufSize; 334 338 335 DSLOGREL(("DSound: cbPlayCursor=%RU32, cbWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n",336 cbPlayCursor, cbWriteCursor, pStreamDS->Out.offWritePos, cbFree));339 DSLOGREL(("DSound: offPlayCursor=%RU32, offWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n", 340 offPlayCursor, offWriteCursor, pStreamDS->Out.offWritePos, cbFree)); 337 341 338 342 *pdwFree = cbFree; 339 343 *poffPlayCursor = offPlayCursor; 340 344 return VINF_SUCCESS; 341 345 } … … 354 358 LogFunc(("Failed with %Rhrc\n", hr)); 355 359 360 *poffPlayCursor = pStreamDS->cbBufSize; 356 361 return VERR_NOT_AVAILABLE; 357 362 } … … 571 576 572 577 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 573 if (FAILED(hr))574 return hr;575 576 DSLOG(("DSound: Closing playback stream\n"));577 578 if (pStreamDS->pCircBuf)579 Assert(RTCircBufUsed(pStreamDS->pCircBuf) == 0);580 581 578 if (SUCCEEDED(hr)) 582 579 { 580 DSLOG(("DSound: Closing playback stream\n")); 583 581 RTCritSectEnter(&pThis->CritSect); 584 585 if (pStreamDS->pCircBuf)586 {587 RTCircBufDestroy(pStreamDS->pCircBuf);588 pStreamDS->pCircBuf = NULL;589 }590 582 591 583 if (pStreamDS->Out.pDSB) … … 755 747 pStreamDS->cbBufSize = bc.dwBufferBytes; 756 748 757 rc = RTCircBufCreate(&pStreamDS->pCircBuf, pStreamDS->cbBufSize * 2 /* Use "double buffering" */);758 AssertRC(rc);759 760 749 pThis->pDSStrmOut = pStreamDS; 761 750 762 751 const uint32_t cfBufSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize); 763 752 764 pCfgAcq->Backend.cFramesBufferSize = cfBufSize;765 pCfgAcq->Backend.cFramesPeriod = cfBufSize / 4;766 pCfgAcq->Backend.cFramesPreBuffering 753 pCfgAcq->Backend.cFramesBufferSize = cfBufSize; 754 pCfgAcq->Backend.cFramesPeriod = cfBufSize / 4; 755 pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod * 2; 767 756 768 757 } while (0); … … 796 785 /* Make sure to get the last playback position and current write position from DirectSound again. 797 786 * Those positions in theory could have changed, re-fetch them to be sure. */ 798 hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB, 799 &pStreamDS->Out.offPlayCursorLastPlayed, &pStreamDS->Out.offWritePos); 800 if (FAILED(hr)) 787 DWORD offPlay = 0; 788 DWORD offWrite = 0; 789 hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlay, &offWrite); 790 if (SUCCEEDED(hr)) 791 { 792 pStreamDS->Out.offPlayCursorLastPlayed = offPlay; 793 pStreamDS->Out.offWritePos = offWrite; 794 } 795 else 801 796 DSLOGREL(("DSound: Re-fetching current position when clearing buffer failed with %Rhrc\n", hr)); 802 797 } 803 }804 805 /**806 * Transfers audio data from the internal buffer to the DirectSound playback instance.807 * Due to internal accounting and querying DirectSound, this function knows how much it can transfer at once.808 *809 * @return IPRT status code.810 * @param pThis Host audio driver instance.811 * @param pStreamDS Stream to transfer playback data for.812 */813 static int dsoundPlayTransfer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)814 {815 if (!pStreamDS->fEnabled)816 {817 Log2Func(("Stream disabled, skipping\n"));818 return VINF_SUCCESS;819 }820 821 uint32_t cbTransferred = 0;822 823 PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;824 AssertPtr(pCircBuf);825 826 LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB;827 AssertPtr(pDSB);828 829 int rc = VINF_SUCCESS;830 831 DWORD offPlayCursor, offWriteCursor;832 HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor);833 if (FAILED(hr))834 {835 rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */836 return rc;837 }838 839 DWORD cbFree, cbRemaining;840 if (pStreamDS->Out.fFirstTransfer)841 {842 cbRemaining = 0;843 cbFree = pStreamDS->cbBufSize;844 }845 else846 {847 cbFree = dsoundRingDistance(offPlayCursor, pStreamDS->Out.offWritePos, pStreamDS->cbBufSize);848 cbRemaining = dsoundRingDistance(pStreamDS->Out.offWritePos, offPlayCursor, pStreamDS->cbBufSize);849 }850 851 uint32_t cbAvail = (uint32_t)RTCircBufUsed(pCircBuf);852 uint32_t cbToTransfer = RT_MIN(cbFree, cbAvail);853 854 #ifdef LOG_ENABLED855 if (!pStreamDS->Dbg.tsLastTransferredMs)856 pStreamDS->Dbg.tsLastTransferredMs = RTTimeMilliTS();857 Log3Func(("offPlay=%RU32, offWrite=%RU32, tsLastTransferredMs=%RU64ms, cbAvail=%RU32, cbFree=%RU32 -> cbToTransfer=%RU32 "858 "(fFirst=%RTbool, fDrain=%RTbool)\n",859 offPlayCursor, offWriteCursor, RTTimeMilliTS() - pStreamDS->Dbg.tsLastTransferredMs, cbAvail, cbFree, cbToTransfer,860 pStreamDS->Out.fFirstTransfer, pStreamDS->Out.fDrain));861 pStreamDS->Dbg.tsLastTransferredMs = RTTimeMilliTS();862 #endif863 864 while (cbToTransfer)865 {866 DWORD cb1 = 0;867 DWORD cb2 = 0;868 869 void *pvBuf;870 size_t cbBuf;871 RTCircBufAcquireReadBlock(pCircBuf, cbToTransfer, &pvBuf, &cbBuf);872 873 if (cbBuf)874 {875 PVOID pv1, pv2;876 hr = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, (DWORD)cbBuf,877 &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);878 if (FAILED(hr))879 {880 rc = VERR_ACCESS_DENIED;881 break;882 }883 884 AssertPtr(pv1);885 Assert(cb1);886 887 memcpy(pv1, pvBuf, cb1);888 889 if (pv2 && cb2) /* Buffer wrap-around? Write second part. */890 memcpy(pv2, (uint8_t *)pvBuf + cb1, cb2);891 892 directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);893 894 pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize;895 896 Assert(cbToTransfer >= cbBuf);897 cbToTransfer -= (uint32_t)cbBuf;898 899 cbTransferred += cb1 + cb2;900 }901 902 RTCircBufReleaseReadBlock(pCircBuf, cb1 + cb2);903 }904 905 pStreamDS->Out.cbTransferred += cbTransferred;906 907 if ( pStreamDS->Out.fFirstTransfer908 && pStreamDS->Out.cbTransferred >= PDMAudioPropsFramesToBytes(&pStreamDS->Cfg.Props, pStreamDS->Cfg.Backend.cFramesPreBuffering))909 {910 hr = directSoundPlayStart(pThis, pStreamDS);911 if (SUCCEEDED(hr))912 {913 pStreamDS->Out.fFirstTransfer = false;914 }915 else916 rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */917 }918 919 cbAvail = (uint32_t)RTCircBufUsed(pCircBuf);920 if ( !cbAvail921 && cbTransferred)922 {923 pStreamDS->Out.cbLastTransferred = cbTransferred;924 pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS();925 926 LogFlowFunc(("cbLastTransferred=%RU32, tsLastTransferredMs=%RU64\n",927 pStreamDS->Out.cbLastTransferred, pStreamDS->Out.tsLastTransferredMs));928 }929 930 LogFlowFunc(("cbTransferred=%RU32, cbAvail=%RU32, rc=%Rrc\n", cbTransferred, cbAvail, rc));931 return rc;932 798 } 933 799 … … 980 846 { 981 847 hr = directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 982 if (FAILED(hr)) 848 if (FAILED(hr)) /** @todo shouldn't this be a SUCCEEDED? */ 983 849 hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB); 984 850 } … … 1034 900 LogFunc(("Resetting %s\n", 1035 901 pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback")); 1036 1037 if (pStreamDS->pCircBuf)1038 RTCircBufReset(pStreamDS->pCircBuf);1039 902 1040 903 if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN) … … 1061 924 else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT) 1062 925 { 926 /* If draining was enagaged, make sure dsound has stopped playing. */ 927 if (pStreamDS->Out.fDrain && pStreamDS->Out.pDSB) 928 pStreamDS->Out.pDSB->Stop(); 929 1063 930 pStreamDS->Out.fFirstTransfer = true; 1064 931 pStreamDS->Out.fDrain = false; … … 1122 989 || hr != DSERR_BUFFERLOST) 1123 990 break; 1124 else 1125 { 1126 LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n")); 1127 directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 1128 } 991 LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n")); 992 directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 1129 993 } 1130 994 … … 1193 1057 1194 1058 /** 1195 * Transfers audio data from the DirectSound capture instance to the internal buffer.1196 * Due to internal accounting and querying DirectSound, this function knows how much it can transfer at once.1197 *1198 * @return IPRT status code.1199 * @param pThis Host audio driver instance.1200 * @param pStreamDS Stream to capture audio data for.1201 */1202 static int dsoundCaptureTransfer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)1203 {1204 RT_NOREF(pThis);1205 1206 LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pStreamDS->In.pDSCB;1207 AssertPtr(pDSCB);1208 1209 DWORD offCaptureCursor;1210 HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &offCaptureCursor);1211 if (FAILED(hr))1212 {1213 AssertFailed();1214 return VERR_ACCESS_DENIED; /** @todo Find a better rc. */1215 }1216 1217 DWORD cbUsed = dsoundRingDistance(offCaptureCursor, pStreamDS->In.offReadPos, pStreamDS->cbBufSize);1218 1219 PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;1220 AssertPtr(pCircBuf);1221 1222 uint32_t cbFree = (uint32_t)RTCircBufFree(pCircBuf);1223 if ( !cbFree1224 && pStreamDS->In.cOverruns < 32) /** @todo Make this configurable. */1225 {1226 DSLOG(("DSound: Warning: Internal buffer full (size is %zu bytes), skipping to record data (overflow #%RU32)\n",1227 RTCircBufSize(pCircBuf), pStreamDS->In.cOverruns));1228 DSLOG(("DSound: Warning: DSound capture buffer currently uses %RU32/%RU32 bytes\n", cbUsed, pStreamDS->cbBufSize));1229 pStreamDS->In.cOverruns++;1230 }1231 1232 DWORD cbToCapture = RT_MIN(cbUsed, cbFree);1233 1234 Log3Func(("cbUsed=%ld, cbToCapture=%ld\n", cbUsed, cbToCapture));1235 1236 while (cbToCapture)1237 {1238 void *pvBuf;1239 size_t cbBuf;1240 RTCircBufAcquireWriteBlock(pCircBuf, cbToCapture, &pvBuf, &cbBuf);1241 1242 if (cbBuf)1243 {1244 PVOID pv1, pv2;1245 DWORD cb1, cb2;1246 hr = directSoundCaptureLock(pStreamDS, pStreamDS->In.offReadPos, (DWORD)cbBuf,1247 &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);1248 if (FAILED(hr))1249 break;1250 1251 AssertPtr(pv1);1252 Assert(cb1);1253 1254 memcpy(pvBuf, pv1, cb1);1255 1256 if (pv2 && cb2) /* Buffer wrap-around? Write second part. */1257 memcpy((uint8_t *)pvBuf + cb1, pv2, cb2);1258 1259 directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);1260 1261 pStreamDS->In.offReadPos = (pStreamDS->In.offReadPos + cb1 + cb2) % pStreamDS->cbBufSize;1262 1263 Assert(cbToCapture >= cbBuf);1264 cbToCapture -= (uint32_t)cbBuf;1265 }1266 1267 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA1268 if (cbBuf)1269 {1270 RTFILE fh;1271 int rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "dsoundCapture.pcm",1272 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);1273 if (RT_SUCCESS(rc2))1274 {1275 RTFileWrite(fh, pvBuf, cbBuf, NULL);1276 RTFileClose(fh);1277 }1278 }1279 #endif1280 RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);1281 }1282 1283 return VINF_SUCCESS;1284 }1285 1286 /**1287 1059 * Destroys a DirectSound capture interface. 1288 1060 * … … 1397 1169 return hr; 1398 1170 1399 do /* To use breaks. */1171 do /* For readability breaks... */ 1400 1172 { 1401 1173 DSCBUFFERDESC bd; … … 1489 1261 pStreamDS->In.offReadPos = 0; 1490 1262 pStreamDS->cbBufSize = bc.dwBufferBytes; 1491 1492 rc = RTCircBufCreate(&pStreamDS->pCircBuf, pStreamDS->cbBufSize * 2 /* Use "double buffering" */);1493 AssertRC(rc);1494 1263 1495 1264 pThis->pDSStrmIn = pStreamDS; … … 2070 1839 LogFlowFunc(("pStreamDS=%p, pCfgReq=%p\n", pStreamDS, pCfgReq)); 2071 1840 2072 int rc = VINF_SUCCESS;1841 int rc; 2073 1842 2074 1843 /* Try to open playback in case the device is already there. */ … … 2091 1860 LogFlowFunc(("pStreamDS=%p, cmd=%d\n", pStreamDS, enmStreamCmd)); 2092 1861 2093 int rc = VINF_SUCCESS;2094 2095 1862 HRESULT hr; 1863 int rc = VINF_SUCCESS; 2096 1864 switch (enmStreamCmd) 2097 1865 { … … 2104 1872 case PDMAUDIOSTREAMCMD_RESUME: 2105 1873 { 2106 hr = directSoundPlayStart(pThis, pStreamDS); 2107 if (FAILED(hr)) 2108 rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */ 1874 /* Only resume if the stream is enabled. 1875 Note! This used to always just resume the stream playback regardless of state, 1876 and instead rely on DISABLE filling the buffer with silence. */ 1877 if (pStreamDS->fEnabled) 1878 { 1879 hr = directSoundPlayStart(pThis, pStreamDS); 1880 if (FAILED(hr)) 1881 rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */ 1882 } 2109 1883 break; 2110 1884 } … … 2113 1887 { 2114 1888 dsoundStreamEnable(pThis, pStreamDS, false /* fEnable */); 2115 hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 2116 if (FAILED(hr)) 2117 rc = VERR_NOT_SUPPORTED; 1889 1890 /* Don't stop draining buffers. They'll stop by themselves. */ 1891 if (pStreamDS->Cfg.enmDir != PDMAUDIODIR_OUT || !pStreamDS->Out.fDrain) 1892 { 1893 hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 1894 if (FAILED(hr)) 1895 rc = VERR_NOT_SUPPORTED; 1896 } 2118 1897 break; 2119 1898 } … … 2130 1909 { 2131 1910 /* Make sure we transferred everything. */ 2132 pStreamDS->fEnabled = true; 2133 pStreamDS->Out.fDrain = true; 2134 rc = dsoundPlayTransfer(pThis, pStreamDS); 2135 if ( RT_SUCCESS(rc) 2136 && pStreamDS->Out.fFirstTransfer) 1911 pStreamDS->fEnabled = true; /** @todo r=bird: ??? */ 1912 1913 /* 1914 * We've started the buffer in looping mode, try switch to non-looping... 1915 */ 1916 if (pStreamDS->Out.pDSB) 2137 1917 { 2138 /* If this was the first transfer ever for this stream, make sure to also play the (short) audio data. */ 2139 DSLOG(("DSound: Started playing output (short sound)\n")); 2140 2141 pStreamDS->Out.fFirstTransfer = false; 2142 pStreamDS->Out.cbLastTransferred = pStreamDS->Out.cbTransferred; /* All transferred audio data must be played. */ 2143 pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS(); 2144 2145 hr = directSoundPlayStart(pThis, pStreamDS); 2146 if (FAILED(hr)) 2147 rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */ 1918 Log2Func(("drain: Switching playback to non-looping mode...\n")); 1919 HRESULT hrc = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB); 1920 if (SUCCEEDED(hrc)) 1921 { 1922 hrc = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, 0); 1923 if (SUCCEEDED(hrc)) 1924 pStreamDS->Out.fDrain = true; 1925 else 1926 Log2Func(("drain: IDirectSoundBuffer8_Play(,,,0) failed: %Rhrc\n", hrc)); 1927 } 1928 else 1929 { 1930 Log2Func(("drain: IDirectSoundBuffer8_Stop failed: %Rhrc\n", hrc)); 1931 hrc = directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 1932 if (SUCCEEDED(hrc)) 1933 { 1934 hrc = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB); 1935 Log2Func(("drain: IDirectSoundBuffer8_Stop failed: %Rhrc\n", hrc)); 1936 } 1937 } 2148 1938 } 2149 1939 break; … … 2154 1944 pStreamDS->Out.cbLastTransferred = 0; 2155 1945 pStreamDS->Out.tsLastTransferredMs = 0; 2156 RTCircBufReset(pStreamDS->pCircBuf);2157 1946 break; 2158 1947 } … … 2170 1959 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay} 2171 1960 */ 2172 static DECLCALLBACK(int) drvHostDSoundHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, const void *pvBuf, 2173 uint32_t uBufSize, uint32_t *puWritten) 2174 { 2175 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2176 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2177 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 2178 AssertReturn(uBufSize, VERR_INVALID_PARAMETER); 2179 /* puWritten is optional. */ 2180 2181 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface); 2182 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2183 2184 int rc = VINF_SUCCESS; 2185 2186 uint32_t cbWrittenTotal = 0; 2187 2188 uint8_t *pbBuf = (uint8_t *)pvBuf; 2189 PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf; 2190 2191 uint32_t cbToPlay = RT_MIN(uBufSize, (uint32_t)RTCircBufFree(pCircBuf)); 2192 while (cbToPlay) 2193 { 2194 void *pvChunk; 2195 size_t cbChunk; 2196 RTCircBufAcquireWriteBlock(pCircBuf, cbToPlay, &pvChunk, &cbChunk); 2197 2198 if (cbChunk) 2199 { 2200 memcpy(pvChunk, pbBuf, cbChunk); 2201 2202 pbBuf += cbChunk; 2203 Assert(cbToPlay >= cbChunk); 2204 cbToPlay -= (uint32_t)cbChunk; 2205 2206 cbWrittenTotal += (uint32_t)cbChunk; 2207 } 2208 2209 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 2210 } 2211 2212 Assert(cbWrittenTotal <= uBufSize); 2213 Assert(cbWrittenTotal == uBufSize); 2214 2215 pStreamDS->Out.cbWritten += cbWrittenTotal; 2216 2217 if (RT_SUCCESS(rc)) 2218 { 2219 if (puWritten) 2220 *puWritten = cbWrittenTotal; 2221 } 1961 static DECLCALLBACK(int) drvHostDSoundHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1962 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 1963 { 1964 PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); 1965 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 1966 AssertPtrReturn(pStreamDS, 0); 1967 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 1968 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 1969 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER); 1970 1971 if (pStreamDS->fEnabled) 1972 AssertReturn(pStreamDS->cbBufSize, VERR_INTERNAL_ERROR_2); 2222 1973 else 2223 dsoundUpdateStatusInternal(pThis); 2224 2225 return rc; 1974 { 1975 Log2Func(("Stream disabled, skipping\n")); 1976 return VINF_SUCCESS; 1977 } 1978 1979 /** @todo Any condition under which we should call dsoundUpdateStatusInternal(pThis) here? 1980 * The old code thought it did so in case of failure, only it couldn't ever fails, so it never did. */ 1981 1982 /* 1983 * Transfer loop. 1984 */ 1985 uint32_t cbWritten = 0; 1986 while (cbBuf > 0) 1987 { 1988 /* 1989 * Figure out how much we can possibly write. 1990 */ 1991 DWORD offPlayCursor = 0; 1992 DWORD cbWritable = 0; 1993 int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbWritable, &offPlayCursor); 1994 AssertRCReturn(rc, rc); 1995 if (cbWritable < pStreamDS->Cfg.Props.cbFrame) 1996 break; 1997 1998 uint32_t const cbToWrite = RT_MIN(cbWritable, cbBuf); 1999 Log3Func(("offPlay=%#x offWritePos=%#x -> cbWritable=%#x cbToWrite=%#x%s%s\n", offPlayCursor, pStreamDS->Out.offWritePos, 2000 cbWritable, cbToWrite, pStreamDS->Out.fFirstTransfer ? " first" : "", pStreamDS->Out.fDrain ? " drain" : "")); 2001 2002 /* 2003 * Lock that amount of buffer. 2004 */ 2005 PVOID pv1 = NULL; 2006 DWORD cb1 = 0; 2007 PVOID pv2 = NULL; 2008 DWORD cb2 = 0; 2009 HRESULT hrc = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, cbToWrite, 2010 &pv1, &pv2, &cb1, &cb2, 0 /*dwFlags*/); 2011 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */ 2012 //AssertMsg(cb1 + cb2 == cbToWrite, ("%#x + %#x vs %#x\n", cb1, cb2, cbToWrite)); 2013 2014 /* 2015 * Copy over the data. 2016 */ 2017 memcpy(pv1, pvBuf, cb1); 2018 pvBuf = (uint8_t *)pvBuf + cb1; 2019 cbBuf -= cb1; 2020 cbWritten += cb1; 2021 2022 if (pv2) 2023 { 2024 memcpy(pv2, pvBuf, cb2); 2025 pvBuf = (uint8_t *)pvBuf + cb2; 2026 cbBuf -= cb2; 2027 cbWritten += cb2; 2028 } 2029 2030 /* 2031 * Unlock and update the write position. 2032 */ 2033 directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2); /** @todo r=bird: pThis + pDSB parameters here for Unlock, but only pThis for Lock. Why? */ 2034 pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize; 2035 2036 /* 2037 * If this was the first chunk, kick off playing. 2038 */ 2039 if (!pStreamDS->Out.fFirstTransfer) 2040 { /* likely */ } 2041 else 2042 { 2043 *pcbWritten = cbWritten; 2044 hrc = directSoundPlayStart(pThis, pStreamDS); 2045 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */ 2046 pStreamDS->Out.fFirstTransfer = false; 2047 } 2048 } 2049 2050 /* 2051 * Done. 2052 */ 2053 *pcbWritten = cbWritten; 2054 2055 pStreamDS->Out.cbTransferred += cbWritten; 2056 if (cbWritten) 2057 { 2058 uint64_t const msPrev = pStreamDS->Out.tsLastTransferredMs; 2059 pStreamDS->Out.cbLastTransferred = cbWritten; 2060 pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS(); 2061 LogFlowFunc(("cbLastTransferred=%RU32, tsLastTransferredMs=%RU64 cMsDelta=%RU64\n", 2062 cbWritten, pStreamDS->Out.tsLastTransferredMs, msPrev ? pStreamDS->Out.tsLastTransferredMs - msPrev : 0)); 2063 } 2064 return VINF_SUCCESS; 2226 2065 } 2227 2066 … … 2334 2173 */ 2335 2174 static DECLCALLBACK(int) drvHostDSoundHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 2336 void *pvBuf, uint32_t uBufSize, uint32_t *puRead) 2337 { 2338 2339 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2340 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2341 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 2342 AssertReturn(uBufSize, VERR_INVALID_PARAMETER); 2343 2344 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface); 2345 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2346 2347 int rc = VINF_SUCCESS; 2348 2349 uint32_t cbReadTotal = 0; 2350 2351 uint32_t cbToRead = RT_MIN((uint32_t)RTCircBufUsed(pStreamDS->pCircBuf), uBufSize); 2352 while (cbToRead) 2353 { 2354 void *pvChunk; 2355 size_t cbChunk; 2356 RTCircBufAcquireReadBlock(pStreamDS->pCircBuf, cbToRead, &pvChunk, &cbChunk); 2357 2358 if (cbChunk) 2359 { 2360 memcpy((uint8_t *)pvBuf + cbReadTotal, pvChunk, cbChunk); 2361 cbReadTotal += (uint32_t)cbChunk; 2362 Assert(cbToRead >= cbChunk); 2363 cbToRead -= (uint32_t)cbChunk; 2364 } 2365 2366 RTCircBufReleaseReadBlock(pStreamDS->pCircBuf, cbChunk); 2367 } 2368 2369 if (RT_SUCCESS(rc)) 2370 { 2371 if (puRead) 2372 *puRead = cbReadTotal; 2373 } 2175 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 2176 { 2177 /*PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);*/ RT_NOREF(pInterface); 2178 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2179 AssertPtrReturn(pStreamDS, 0); 2180 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 2181 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 2182 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER); 2183 2184 #if 0 /** @todo r=bird: shouldn't we do the same check as for output streams? */ 2185 if (pStreamDS->fEnabled) 2186 AssertReturn(pStreamDS->cbBufSize, VERR_INTERNAL_ERROR_2); 2374 2187 else 2375 dsoundUpdateStatusInternal(pThis); 2376 2377 return rc; 2188 { 2189 Log2Func(("Stream disabled, skipping\n")); 2190 return VINF_SUCCESS; 2191 } 2192 #endif 2193 2194 /* 2195 * Read loop. 2196 */ 2197 uint32_t cbRead = 0; 2198 while (cbBuf > 0) 2199 { 2200 /* 2201 * Figure out how much we can read. 2202 */ 2203 DWORD offCaptureCursor = 0; 2204 DWORD offReadCursor = 0; 2205 HRESULT hrc = IDirectSoundCaptureBuffer_GetCurrentPosition(pStreamDS->In.pDSCB, &offCaptureCursor, &offReadCursor); 2206 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */ 2207 //AssertMsg(offReadCursor == pStreamDS->In.offReadPos, ("%#x %#x\n", offReadCursor, pStreamDS->In.offReadPos)); 2208 2209 uint32_t const cbReadable = dsoundRingDistance(offCaptureCursor, pStreamDS->In.offReadPos, pStreamDS->cbBufSize); 2210 2211 if (cbReadable >= pStreamDS->Cfg.Props.cbFrame) 2212 { /* likely */ } 2213 else 2214 { 2215 if (cbRead > 0) 2216 { /* likely */ } 2217 else if (pStreamDS->In.cOverruns < 32) 2218 { 2219 pStreamDS->In.cOverruns++; 2220 DSLOG(("DSound: Warning: Buffer full (size is %zu bytes), skipping to record data (overflow #%RU32)\n", 2221 pStreamDS->cbBufSize, pStreamDS->In.cOverruns)); 2222 } 2223 break; 2224 } 2225 2226 uint32_t const cbToRead = RT_MIN(cbReadable, cbBuf); 2227 Log3Func(("offCapture=%#x offRead=%#x/%#x -> cbWritable=%#x cbToWrite=%#x\n", 2228 offCaptureCursor, offReadCursor, pStreamDS->In.offReadPos, cbReadable, cbToRead)); 2229 2230 /* 2231 * Lock that amount of buffer. 2232 */ 2233 PVOID pv1 = NULL; 2234 DWORD cb1 = 0; 2235 PVOID pv2 = NULL; 2236 DWORD cb2 = 0; 2237 hrc = directSoundCaptureLock(pStreamDS, pStreamDS->In.offReadPos, cbToRead, &pv1, &pv2, &cb1, &cb2, 0 /*dwFlags*/); 2238 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */ 2239 AssertMsg(cb1 + cb2 == cbToRead, ("%#x + %#x vs %#x\n", cb1, cb2, cbToRead)); 2240 2241 /* 2242 * Copy over the data. 2243 */ 2244 memcpy(pvBuf, pv1, cb1); 2245 pvBuf = (uint8_t *)pvBuf + cb1; 2246 cbBuf -= cb1; 2247 cbRead += cb1; 2248 2249 if (pv2) 2250 { 2251 memcpy(pvBuf, pv2, cb2); 2252 pvBuf = (uint8_t *)pvBuf + cb2; 2253 cbBuf -= cb2; 2254 cbRead += cb2; 2255 } 2256 2257 /* 2258 * Unlock and update the write position. 2259 */ 2260 directSoundCaptureUnlock(pStreamDS->In.pDSCB, pv1, pv2, cb1, cb2); /** @todo r=bird: pDSB parameter here for Unlock, but pStreamDS for Lock. Why? */ 2261 pStreamDS->In.offReadPos = (pStreamDS->In.offReadPos + cb1 + cb2) % pStreamDS->cbBufSize; 2262 } 2263 2264 /* 2265 * Done. 2266 */ 2267 if (pcbRead) 2268 *pcbRead = cbRead; 2269 2270 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA 2271 if (cbRead) 2272 { 2273 RTFILE hFile; 2274 int rc2 = RTFileOpen(&hFile, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "dsoundCapture.pcm", 2275 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 2276 if (RT_SUCCESS(rc2)) 2277 { 2278 RTFileWrite(hFile, (uint8_t *)pvBuf - cbRead, cbRead, NULL); 2279 RTFileClose(hFile); 2280 } 2281 } 2282 #endif 2283 return VINF_SUCCESS; 2378 2284 } 2379 2285 … … 2606 2512 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 2607 2513 { 2514 /*PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface); 2515 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2516 AssertPtrReturn(pStreamDS, 0); 2517 Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN); 2518 2519 if (pStreamDS->fEnabled) 2520 { 2521 /* This is the same calculation as for StreamGetPending. */ 2522 AssertPtr(pStreamDS->In.pDSCB); 2523 DWORD offCaptureCursor = 0; 2524 DWORD offReadCursor = 0; 2525 HRESULT hrc = IDirectSoundCaptureBuffer_GetCurrentPosition(pStreamDS->In.pDSCB, &offCaptureCursor, &offReadCursor); 2526 if (SUCCEEDED(hrc)) 2527 { 2528 uint32_t cbPending = dsoundRingDistance(offCaptureCursor, offReadCursor, pStreamDS->cbBufSize); 2529 Log3Func(("cbPending=%RU32\n", cbPending)); 2530 return cbPending; 2531 } 2532 AssertMsgFailed(("hrc=%Rhrc\n", hrc)); 2533 } 2534 2535 return 0; 2536 } 2537 2538 /** 2539 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable} 2540 */ 2541 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 2542 { 2543 PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); 2544 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2545 AssertPtrReturn(pStreamDS, 0); 2546 2547 DWORD cbFree = 0; 2548 DWORD offIgn = 0; 2549 int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree, &offIgn); 2550 AssertRCReturn(rc, 0); 2551 2552 return cbFree; 2553 } 2554 2555 #if 0 /* This isn't working as the write cursor is more a function of time than what we do. 2556 Previously we only reported the pre-buffering status anyway, so no harm. */ 2557 /** 2558 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending} 2559 */ 2560 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 2561 { 2562 /*PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface); 2563 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2564 AssertPtrReturn(pStreamDS, 0); 2565 2566 if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT) 2567 { 2568 /* This is a similar calculation as for StreamGetReadable, only for an output buffer. */ 2569 AssertPtr(pStreamDS->In.pDSCB); 2570 DWORD offPlayCursor = 0; 2571 DWORD offWriteCursor = 0; 2572 HRESULT hrc = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor); 2573 if (SUCCEEDED(hrc)) 2574 { 2575 uint32_t cbPending = dsoundRingDistance(offWriteCursor, offPlayCursor, pStreamDS->cbBufSize); 2576 Log3Func(("cbPending=%RU32\n", cbPending)); 2577 return cbPending; 2578 } 2579 AssertMsgFailed(("hrc=%Rhrc\n", hrc)); 2580 } 2581 /* else: For input streams we never have any pending data. */ 2582 2583 return 0; 2584 } 2585 #endif 2586 2587 /** 2588 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus} 2589 */ 2590 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 2591 { 2608 2592 RT_NOREF(pInterface); 2609 2593 AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE); … … 2611 2595 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2612 2596 2613 if ( pStreamDS->fEnabled2614 && pStreamDS->pCircBuf)2615 {2616 return (uint32_t)RTCircBufUsed(pStreamDS->pCircBuf);2617 }2618 2619 return 0;2620 }2621 2622 /**2623 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}2624 */2625 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)2626 {2627 AssertPtrReturn(pInterface, PDMAUDIOSTREAMSTS_FLAGS_NONE);2628 AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE);2629 2630 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;2631 2632 if (pStreamDS->fEnabled)2633 return (uint32_t)RTCircBufFree(pStreamDS->pCircBuf);2634 2635 return 0;2636 }2637 2638 /**2639 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}2640 */2641 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)2642 {2643 RT_NOREF(pInterface);2644 AssertPtrReturn(pStream, 0);2645 2646 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;2647 2648 if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)2649 {2650 uint32_t cbPending = 0;2651 2652 /* Any uncommitted data left? */2653 if (pStreamDS->pCircBuf)2654 cbPending = (uint32_t)RTCircBufUsed(pStreamDS->pCircBuf);2655 2656 /* Check if we have committed data which still needs to be played by2657 * by DirectSound's streaming buffer. */2658 if (!cbPending)2659 {2660 const uint64_t diffLastTransferredMs = RTTimeMilliTS() - pStreamDS->Out.tsLastTransferredMs;2661 const uint64_t uLastTranserredChunkMs = PDMAudioPropsBytesToMilli(&pStreamDS->Cfg.Props, pStreamDS->Out.cbLastTransferred);2662 if ( uLastTranserredChunkMs2663 && diffLastTransferredMs < uLastTranserredChunkMs)2664 cbPending = 1;2665 2666 Log3Func(("diffLastTransferredMs=%RU64ms, uLastTranserredChunkMs=%RU64ms (%RU32 bytes) -> cbPending=%RU32\n",2667 diffLastTransferredMs, uLastTranserredChunkMs, pStreamDS->Out.cbLastTransferred, cbPending));2668 }2669 else2670 Log3Func(("cbPending=%RU32\n", cbPending));2671 2672 return cbPending;2673 }2674 /* Note: For input streams we never have pending data left. */2675 2676 return 0;2677 }2678 2679 /**2680 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}2681 */2682 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)2683 {2684 RT_NOREF(pInterface);2685 AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE);2686 2687 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;2688 2689 2597 PDMAUDIOSTREAMSTS fStrmStatus = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED; 2690 2598 … … 2700 2608 static DECLCALLBACK(int) drvHostDSoundHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 2701 2609 { 2702 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2703 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2704 2705 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface); 2706 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2707 2708 if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN) 2709 { 2710 return dsoundCaptureTransfer(pThis, pStreamDS); 2711 } 2712 else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT) 2713 { 2714 return dsoundPlayTransfer(pThis, pStreamDS); 2715 } 2716 2610 RT_NOREF(pInterface, pStream); 2717 2611 return VINF_SUCCESS; 2718 2612 } … … 2813 2707 pThis->IHostAudio.pfnStreamCapture = drvHostDSoundHA_StreamCapture; 2814 2708 pThis->IHostAudio.pfnGetDevices = drvHostDSoundHA_GetDevices; 2815 pThis->IHostAudio.pfnStreamGetPending = drvHostDSoundHA_StreamGetPending;2709 pThis->IHostAudio.pfnStreamGetPending = NULL; 2816 2710 pThis->IHostAudio.pfnStreamPlayBegin = NULL; 2817 2711 pThis->IHostAudio.pfnStreamPlayEnd = NULL;
Note:
See TracChangeset
for help on using the changeset viewer.