Changeset 88554 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 15, 2021 10:20:26 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143849
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioDSound.cpp
r88542 r88554 47 47 *********************************************************************************************************************************/ 48 48 /* 49 * IDirectSound* interface uses HRESULT status codes and the driver callbacks use50 * the VBox status codes. To minimize HRESULT->VBox conversion most internal functions51 * in the driver return HRESULT and conversion is done in the driver callbacks.52 *53 * Naming convention:54 * 'dsound*' functions return VBox status code;55 * 'directSound*' - return HRESULT.56 */57 58 /*59 49 * Optional release logging, which a user can turn on with the 60 50 * 'VBoxManage debugvm' command. 61 51 * Debug logging still uses the common Log* macros from VBox. 62 52 * Messages which always should go to the release log use LogRel. 53 * 54 * @deprecated Use LogRelMax, LogRel2 and LogRel3 directly. 63 55 */ 64 56 /** General code behavior. */ … … 78 70 /** Maximum number of attempts to restore the sound buffer before giving up. */ 79 71 #define DRV_DSOUND_RESTORE_ATTEMPTS_MAX 3 72 #if 0 /** @todo r=bird: What are these for? Nobody is using them... */ 80 73 /** Default input latency (in ms). */ 81 74 #define DRV_DSOUND_DEFAULT_LATENCY_MS_IN 50 82 75 /** Default output latency (in ms). */ 83 76 #define DRV_DSOUND_DEFAULT_LATENCY_MS_OUT 50 84 85 /** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */ 86 #define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \ 87 ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_UOFFSETOF(DRVHOSTDSOUND, IHostAudio)) ) 77 #endif 88 78 89 79 … … 248 238 249 239 static int dsoundStreamEnable(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fEnable); 250 static void dsoundStreamReset(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS);251 240 static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis); 252 241 … … 407 396 408 397 /** 409 * Destroys a DirectSound playback interface. 410 * 411 * @param pDS Playback interface to destroy. 412 */ 413 static void directSoundPlayInterfaceDestroy(LPDIRECTSOUND8 pDS) 414 { 415 if (pDS) 416 { 417 LogFlowFuncEnter(); 418 419 IDirectSound8_Release(pDS); 420 pDS = NULL; 421 } 422 } 423 424 425 /** 426 * Creates a DirectSound playback interface. 398 * Creates a DirectSound playback instance. 427 399 * 428 400 * @return HRESULT 429 * @param pGUID GUID of device to create the playback interface for. 430 * @param ppDS Where to store the created interface. Optional. 431 */ 432 static HRESULT directSoundPlayInterfaceCreate(LPCGUID pGUID, LPDIRECTSOUND8 *ppDS) 433 { 434 /* pGUID can be NULL, if this is the default device. */ 435 /* ppDS is optional. */ 436 401 * @param pGUID GUID of device to create the playback interface for. NULL 402 * for the default device. 403 * @param ppDS Where to return the interface to the created instance. 404 */ 405 static HRESULT drvHostDSoundCreateDSPlaybackInstance(LPCGUID pGUID, LPDIRECTSOUND8 *ppDS) 406 { 437 407 LogFlowFuncEnter(); 438 408 439 LPDIRECTSOUND8 pDS; 440 HRESULT hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL, 441 IID_IDirectSound8, (void **)&pDS); 442 if (FAILED(hr)) 443 { 444 DSLOGREL(("DSound: Creating playback instance failed with %Rhrc\n", hr)); 409 LPDIRECTSOUND8 pDS = NULL; 410 HRESULT hrc = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL, IID_IDirectSound8, (void **)&pDS); 411 if (SUCCEEDED(hrc)) 412 { 413 hrc = IDirectSound8_Initialize(pDS, pGUID); 414 if (SUCCEEDED(hrc)) 415 { 416 HWND hWnd = GetDesktopWindow(); 417 hrc = IDirectSound8_SetCooperativeLevel(pDS, hWnd, DSSCL_PRIORITY); 418 if (SUCCEEDED(hrc)) 419 { 420 *ppDS = pDS; 421 LogFlowFunc(("LEAVE S_OK\n")); 422 return S_OK; 423 } 424 LogRelMax(64, ("DSound: Setting cooperative level for (hWnd=%p) failed: %Rhrc\n", hWnd, hrc)); 425 } 426 else if (hrc == DSERR_NODRIVER) /* Usually means that no playback devices are attached. */ 427 LogRelMax(64, ("DSound: DirectSound playback is currently unavailable\n")); 428 else 429 LogRelMax(64, ("DSound: DirectSound playback initialization failed: %Rhrc\n", hrc)); 430 431 IDirectSound8_Release(pDS); 445 432 } 446 433 else 447 { 448 hr = IDirectSound8_Initialize(pDS, pGUID); 449 if (SUCCEEDED(hr)) 450 { 451 HWND hWnd = GetDesktopWindow(); 452 hr = IDirectSound8_SetCooperativeLevel(pDS, hWnd, DSSCL_PRIORITY); 453 if (FAILED(hr)) 454 DSLOGREL(("DSound: Setting cooperative level for window %p failed with %Rhrc\n", hWnd, hr)); 455 } 456 457 if (FAILED(hr)) 458 { 459 if (hr == DSERR_NODRIVER) /* Usually means that no playback devices are attached. */ 460 DSLOGREL(("DSound: DirectSound playback is currently unavailable\n")); 461 else 462 DSLOGREL(("DSound: DirectSound playback initialization failed with %Rhrc\n", hr)); 463 464 directSoundPlayInterfaceDestroy(pDS); 465 } 466 else if (ppDS) 467 { 468 *ppDS = pDS; 469 } 470 } 471 472 LogFlowFunc(("Returning %Rhrc\n", hr)); 473 return hr; 474 } 475 476 434 LogRelMax(64, ("DSound: Creating playback instance failed: %Rhrc\n", hrc)); 435 436 LogFlowFunc(("LEAVE %Rhrc\n", hrc)); 437 return hrc; 438 } 439 440 441 #if 0 /* not used */ 477 442 static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus) 478 443 { … … 508 473 return hr; 509 474 } 475 #endif 510 476 511 477 … … 571 537 572 538 /** 573 * Destroys a DirectSound capture interface.539 * Creates a DirectSound capture instance. 574 540 * 575 * @param pDSC Capture interface to destroy. 576 */ 577 static void directSoundCaptureInterfaceDestroy(LPDIRECTSOUNDCAPTURE8 pDSC) 578 { 579 if (pDSC) 580 { 581 LogFlowFuncEnter(); 582 541 * @returns HRESULT 542 * @param pGUID GUID of device to create the capture interface for. NULL 543 * for default. 544 * @param ppDSC Where to return the interface to the created instance. 545 */ 546 static HRESULT drvHostDSoundCreateDSCaptureInstance(LPCGUID pGUID, LPDIRECTSOUNDCAPTURE8 *ppDSC) 547 { 548 LogFlowFuncEnter(); 549 550 LPDIRECTSOUNDCAPTURE8 pDSC = NULL; 551 HRESULT hrc = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL, IID_IDirectSoundCapture8, (void **)&pDSC); 552 if (SUCCEEDED(hrc)) 553 { 554 hrc = IDirectSoundCapture_Initialize(pDSC, pGUID); 555 if (SUCCEEDED(hrc)) 556 { 557 *ppDSC = pDSC; 558 LogFlowFunc(("LEAVE S_OK\n")); 559 return S_OK; 560 } 561 if (hrc == DSERR_NODRIVER) /* Usually means that no capture devices are attached. */ 562 LogRelMax(64, ("DSound: Capture device currently is unavailable\n")); 563 else 564 LogRelMax(64, ("DSound: Initializing capturing device failed: %Rhrc\n", hrc)); 583 565 IDirectSoundCapture_Release(pDSC); 584 pDSC = NULL;585 }586 }587 588 589 /**590 * Creates a DirectSound capture interface.591 *592 * @return HRESULT593 * @param pGUID GUID of device to create the capture interface for.594 * @param ppDSC Where to store the created interface. Optional.595 */596 static HRESULT directSoundCaptureInterfaceCreate(LPCGUID pGUID, LPDIRECTSOUNDCAPTURE8 *ppDSC)597 {598 /* pGUID can be NULL, if this is the default device. */599 /* ppDSC is optional. */600 601 LogFlowFuncEnter();602 603 LPDIRECTSOUNDCAPTURE8 pDSC;604 HRESULT hr = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL,605 IID_IDirectSoundCapture8, (void **)&pDSC);606 if (FAILED(hr))607 {608 DSLOGREL(("DSound: Creating capture instance failed with %Rhrc\n", hr));609 566 } 610 567 else 611 { 612 hr = IDirectSoundCapture_Initialize(pDSC, pGUID); 613 if (FAILED(hr)) 614 { 615 if (hr == DSERR_NODRIVER) /* Usually means that no capture devices are attached. */ 616 DSLOGREL(("DSound: Capture device currently is unavailable\n")); 617 else 618 DSLOGREL(("DSound: Initializing capturing device failed with %Rhrc\n", hr)); 619 620 directSoundCaptureInterfaceDestroy(pDSC); 621 } 622 else if (ppDSC) 623 { 624 *ppDSC = pDSC; 625 } 626 } 627 628 LogFlowFunc(("Returning %Rhrc\n", hr)); 629 return hr; 568 LogRelMax(64, ("DSound: Creating capture instance failed: %Rhrc\n", hrc)); 569 570 LogFlowFunc(("LEAVE %Rhrc\n", hrc)); 571 return hrc; 630 572 } 631 573 … … 832 774 { 833 775 LPDIRECTSOUND8 pDS; 834 HRESULT hr = d irectSoundPlayInterfaceCreate(&pDev->Guid, &pDS);776 HRESULT hr = drvHostDSoundCreateDSPlaybackInstance(&pDev->Guid, &pDS); 835 777 if (SUCCEEDED(hr)) 836 778 { … … 879 821 } 880 822 881 directSoundPlayInterfaceDestroy(pDS);823 IDirectSound8_Release(pDS); 882 824 } 883 825 else … … 887 829 { 888 830 LPDIRECTSOUNDCAPTURE8 pDSC; 889 HRESULT hr = d irectSoundCaptureInterfaceCreate(&pDev->Guid, &pDSC);831 HRESULT hr = drvHostDSoundCreateDSCaptureInstance(&pDev->Guid, &pDSC); 890 832 if (SUCCEEDED(hr)) 891 833 { … … 905 847 } 906 848 907 directSoundCaptureInterfaceDestroy(pDSC);849 IDirectSoundCapture_Release(pDSC); 908 850 } 909 851 else … … 1183 1125 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDSoundHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir) 1184 1126 { 1185 RT_NOREF(enmDir); 1186 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN); 1187 1127 RT_NOREF(pInterface, enmDir); 1188 1128 return PDMAUDIOBACKENDSTS_RUNNING; 1189 1129 } 1190 1130 1191 1131 1192 static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt) 1193 { 1194 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 1195 AssertPtrReturn(pFmt, VERR_INVALID_POINTER); 1196 1197 RT_BZERO(pFmt, sizeof(WAVEFORMATEX)); 1198 1132 /** 1133 * Converts from PDM stream config to windows WAVEFORMATEX struct. 1134 * 1135 * @param pCfg The PDM audio stream config to convert from. 1136 * @param pFmt The windows structure to initialize. 1137 */ 1138 static void dsoundWaveFmtFromCfg(PCPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt) 1139 { 1140 RT_ZERO(*pFmt); 1199 1141 pFmt->wFormatTag = WAVE_FORMAT_PCM; 1200 1142 pFmt->nChannels = PDMAudioPropsChannels(&pCfg->Props); … … 1204 1146 pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes(&pCfg->Props, PDMAudioPropsHz(&pCfg->Props)); 1205 1147 pFmt->cbSize = 0; /* No extra data specified. */ 1206 1207 return VINF_SUCCESS; 1208 } 1209 1210 1211 /** 1212 * Resets the state of a DirectSound stream. 1148 } 1149 1150 1151 /** 1152 * Resets the state of a DirectSound stream, clearing the buffer content. 1213 1153 * 1214 1154 * @param pThis Host audio driver instance. 1215 1155 * @param pStreamDS Stream to reset state for. 1216 1156 */ 1217 static void d soundStreamReset(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)1157 static void drvHostDSoundStreamReset(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1218 1158 { 1219 1159 RT_NOREF(pThis); 1220 1221 LogFunc(("Resetting %s\n", 1222 pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback")); 1160 LogFunc(("Resetting %s\n", pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback")); 1223 1161 1224 1162 if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN) 1225 1163 { 1164 /* 1165 * Input streams. 1166 */ 1167 LogFunc(("Resetting capture stream '%s'\n", pStreamDS->Cfg.szName)); 1168 1169 /* Reset the state: */ 1170 /** @todo r=bird: We set the read position to zero here, but shouldn't we query it 1171 * from the buffer instead given that there isn't any interface for repositioning 1172 * to the start of the buffer as with playback buffers? */ 1226 1173 pStreamDS->In.offReadPos = 0; 1227 1174 pStreamDS->In.cOverruns = 0; 1228 1175 1229 /* Also reset the DirectSound Capture Buffer (DSCB) by clearing all data to make sure1230 * not stale audio data is left. */1176 /* Clear the buffer content: */ 1177 AssertPtr(pStreamDS->In.pDSCB); 1231 1178 if (pStreamDS->In.pDSCB) 1232 1179 { 1233 PVOID pv1; PVOID pv2; DWORD cb1; DWORD cb2; 1234 HRESULT hr = directSoundCaptureLock(pStreamDS, 0 /* Offset */, pStreamDS->cbBufSize, &pv1, &pv2, &cb1, &cb2, 1235 0 /* Flags */); 1236 if (SUCCEEDED(hr)) 1180 PVOID pv1 = NULL; 1181 DWORD cb1 = 0; 1182 PVOID pv2 = NULL; 1183 DWORD cb2 = 0; 1184 HRESULT hrc = IDirectSoundCaptureBuffer8_Lock(pStreamDS->In.pDSCB, 0, pStreamDS->cbBufSize, 1185 &pv1, &cb1, &pv2, &cb2, 0 /*fFlags*/); 1186 if (SUCCEEDED(hrc)) 1237 1187 { 1238 1188 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1)); 1239 1189 if (pv2 && cb2) 1240 1190 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2)); 1241 directSoundCaptureUnlock(pStreamDS->In.pDSCB, pv1, pv2, cb1, cb2); 1191 hrc = IDirectSoundCaptureBuffer8_Unlock(pStreamDS->In.pDSCB, pv1, cb1, pv2, cb2); 1192 if (FAILED(hrc)) 1193 LogRelMaxFunc(64, ("DSound: Unlocking capture buffer '%s' after reset failed: %Rhrc\n", 1194 pStreamDS->Cfg.szName, hrc)); 1242 1195 } 1243 } 1244 } 1245 else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT) 1246 { 1247 /* If draining was enagaged, make sure dsound has stopped playing. */ 1196 else 1197 LogRelMaxFunc(64, ("DSound: Locking capture buffer '%s' for reset failed: %Rhrc\n", 1198 pStreamDS->Cfg.szName, hrc)); 1199 } 1200 } 1201 else 1202 { 1203 /* 1204 * Output streams. 1205 */ 1206 Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT); 1207 LogFunc(("Resetting playback stream '%s'\n", pStreamDS->Cfg.szName)); 1208 1209 /* If draining was enagaged, make sure dsound has stopped playing: */ 1248 1210 if (pStreamDS->Out.fDrain && pStreamDS->Out.pDSB) 1249 1211 pStreamDS->Out.pDSB->Stop(); 1250 1212 1251 pStreamDS->Out.fFirstTransfer = true; 1252 pStreamDS->Out.fDrain = false; 1253 pStreamDS->Out.cUnderruns = 0; 1254 1255 pStreamDS->Out.cbLastTransferred = 0; 1256 pStreamDS->Out.tsLastTransferredMs = 0; 1257 1258 pStreamDS->Out.cbTransferred = 0; 1259 pStreamDS->Out.cbWritten = 0; 1260 1261 pStreamDS->Out.offWritePos = 0; 1213 /* Reset the internal state: */ 1214 pStreamDS->Out.fFirstTransfer = true; 1215 pStreamDS->Out.fDrain = false; 1216 pStreamDS->Out.cUnderruns = 0; 1217 pStreamDS->Out.cbLastTransferred = 0; 1218 pStreamDS->Out.tsLastTransferredMs = 0; 1219 pStreamDS->Out.cbTransferred = 0; 1220 pStreamDS->Out.cbWritten = 0; 1221 pStreamDS->Out.offWritePos = 0; 1262 1222 pStreamDS->Out.offPlayCursorLastPending = 0; 1263 pStreamDS->Out.offPlayCursorLastPlayed = 0;1264 1265 /* Also reset the DirectSound Buffer (DSB) by setting the position to 0 and clear all data to make sure1266 * not stale audio data is left. */1223 pStreamDS->Out.offPlayCursorLastPlayed = 0; 1224 1225 /* Reset the buffer content and repositioning the buffer to the start of the buffer. */ 1226 AssertPtr(pStreamDS->Out.pDSB); 1267 1227 if (pStreamDS->Out.pDSB) 1268 1228 { 1269 HRESULT hr = IDirectSoundBuffer8_SetCurrentPosition(pStreamDS->Out.pDSB, 0); 1270 if (SUCCEEDED(hr)) 1229 HRESULT hrc = IDirectSoundBuffer8_SetCurrentPosition(pStreamDS->Out.pDSB, 0); 1230 if (FAILED(hrc)) 1231 LogRelMaxFunc(64, ("DSound: Failed to set buffer position for '%s': %Rhrc\n", pStreamDS->Cfg.szName, hrc)); 1232 1233 PVOID pv1 = NULL; 1234 DWORD cb1 = 0; 1235 PVOID pv2 = NULL; 1236 DWORD cb2 = 0; 1237 hrc = IDirectSoundBuffer8_Lock(pStreamDS->Out.pDSB, 0, pStreamDS->cbBufSize, &pv1, &cb1, &pv2, &cb2, 0 /*fFlags*/); 1238 if (hrc == DSERR_BUFFERLOST) 1271 1239 { 1272 PVOID pv1; PVOID pv2; DWORD cb1; DWORD cb2; 1273 hr = directSoundPlayLock(pThis, pStreamDS, 0 /* Offset */, pStreamDS->cbBufSize, &pv1, &pv2, &cb1, &cb2, 1274 0 /* Flags */); 1275 if (SUCCEEDED(hr)) 1276 { 1277 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1)); 1278 if (pv2 && cb2) 1279 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2)); 1280 directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2); 1281 } 1240 directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 1241 hrc = IDirectSoundBuffer8_Lock(pStreamDS->Out.pDSB, 0, pStreamDS->cbBufSize, &pv1, &cb1, &pv2, &cb2, 0 /*fFlags*/); 1282 1242 } 1243 if (SUCCEEDED(hrc)) 1244 { 1245 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1)); 1246 if (pv2 && cb2) 1247 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2)); 1248 1249 hrc = IDirectSoundBuffer8_Unlock(pStreamDS->Out.pDSB, pv1, cb1, pv2, cb2); 1250 if (FAILED(hrc)) 1251 LogRelMaxFunc(64, ("DSound: Unlocking playback buffer '%s' after reset failed: %Rhrc\n", 1252 pStreamDS->Cfg.szName, hrc)); 1253 } 1254 else 1255 LogRelMaxFunc(64, ("DSound: Locking playback buffer '%s' for reset failed: %Rhrc\n", pStreamDS->Cfg.szName, hrc)); 1283 1256 } 1284 1257 } … … 1290 1263 1291 1264 1265 /** 1266 * Worker for drvHostDSoundHA_StreamCreate that creates caputre stream. 1267 * 1268 * @returns Windows COM status code. 1269 * @param pThis The DSound instance data. 1270 * @param pStreamDS The stream instance data. 1271 * @param pCfgReq The requested stream config (input). 1272 * @param pCfgAcq Where to return the actual stream config. This is a 1273 * copy of @a *pCfgReq when called. 1274 * @param pWaveFmtX On input the requested stream format. 1275 * Updated to the actual stream format on successful 1276 * return. 1277 */ 1278 static HRESULT drvHostDSoundStreamCreateCapture(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, 1279 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, WAVEFORMATEX *pWaveFmtX) 1280 { 1281 Assert(pStreamDS->In.pDSCB == NULL); 1282 HRESULT hrc; 1283 1284 /* 1285 * Create, initialize and set up a IDirectSoundCapture instance the first time 1286 * we go thru here. 1287 */ 1288 /** @todo bird: Or should we rather just throw this away after we've gotten the 1289 * capture buffer? Old code would just leak it... */ 1290 if (pThis->pDSC == NULL) 1291 { 1292 hrc = drvHostDSoundCreateDSCaptureInstance(pThis->Cfg.pGuidCapture, &pThis->pDSC); 1293 if (FAILED(hrc)) 1294 return hrc; /* The worker has complained to the release log already. */ 1295 } 1296 1297 /* 1298 * Create the capture buffer. 1299 */ 1300 DSCBUFFERDESC BufferDesc = 1301 { 1302 /*.dwSize = */ sizeof(BufferDesc), 1303 /*.dwFlags = */ 0, 1304 /*.dwBufferBytes =*/ PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize), 1305 /*.dwReserved = */ 0, 1306 /*.lpwfxFormat = */ pWaveFmtX, 1307 /*.dwFXCount = */ 0, 1308 /*.lpDSCFXDesc = */ NULL 1309 }; 1310 1311 LogRel2(("DSound: Requested capture buffer is %#x B / %u B / %RU64 ms\n", BufferDesc.dwBufferBytes, BufferDesc.dwBufferBytes, 1312 PDMAudioPropsBytesToMilli(&pCfgReq->Props, BufferDesc.dwBufferBytes))); 1313 1314 LPDIRECTSOUNDCAPTUREBUFFER pLegacyDSCB = NULL; 1315 hrc = IDirectSoundCapture_CreateCaptureBuffer(pThis->pDSC, &BufferDesc, &pLegacyDSCB, NULL); 1316 if (FAILED(hrc)) 1317 { 1318 LogRelMax(64, ("DSound: Creating capture buffer for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1319 return hrc; 1320 } 1321 1322 /* Get the IDirectSoundCaptureBuffer8 version of the interface. */ 1323 hrc = IDirectSoundCaptureBuffer_QueryInterface(pLegacyDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pStreamDS->In.pDSCB); 1324 IDirectSoundCaptureBuffer_Release(pLegacyDSCB); 1325 if (FAILED(hrc)) 1326 { 1327 LogRelMax(64, ("DSound: Querying IID_IDirectSoundCaptureBuffer8 for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1328 return hrc; 1329 } 1330 1331 /* 1332 * Query the actual stream configuration. 1333 */ 1334 #if 0 /** @todo r=bird: WTF was this for? */ 1335 DWORD offByteReadPos = 0; 1336 hrc = IDirectSoundCaptureBuffer8_GetCurrentPosition(pStreamDS->In.pDSCB, NULL, &offByteReadPos); 1337 if (FAILED(hrc)) 1338 { 1339 offByteReadPos = 0; 1340 DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr)); 1341 } 1342 #endif 1343 RT_ZERO(*pWaveFmtX); 1344 hrc = IDirectSoundCaptureBuffer8_GetFormat(pStreamDS->In.pDSCB, pWaveFmtX, sizeof(*pWaveFmtX), NULL); 1345 if (SUCCEEDED(hrc)) 1346 { 1347 /** @todo r=bird: We aren't converting/checking the pWaveFmtX content... */ 1348 1349 DSCBCAPS BufferCaps = { /*.dwSize = */ sizeof(BufferCaps), 0, 0, 0 }; 1350 hrc = IDirectSoundCaptureBuffer8_GetCaps(pStreamDS->In.pDSCB, &BufferCaps); 1351 if (SUCCEEDED(hrc)) 1352 { 1353 LogRel2(("DSound: Acquired capture buffer capabilities for '%s':\n" 1354 "DSound: dwFlags = %#RX32\n" 1355 "DSound: dwBufferBytes = %#RX32 B / %RU32 B / %RU64 ms\n" 1356 "DSound: dwReserved = %#RX32\n", 1357 pCfgReq->szName, BufferCaps.dwFlags, BufferCaps.dwBufferBytes, BufferCaps.dwBufferBytes, 1358 PDMAudioPropsBytesToMilli(&pCfgReq->Props, BufferCaps.dwBufferBytes), BufferCaps.dwReserved )); 1359 1360 /* Update buffer related stuff: */ 1361 pStreamDS->In.offReadPos = 0; /** @todo shouldn't we use offBytReadPos here to "read at the initial capture position"? */ 1362 pStreamDS->cbBufSize = BufferCaps.dwBufferBytes; 1363 pCfgAcq->Backend.cFramesBufferSize = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, BufferCaps.dwBufferBytes); 1364 1365 /** @todo r=bird: WTF is this for? */ 1366 pThis->pDSStrmIn = pStreamDS; 1367 1368 #if 0 /** @todo r=bird: uAlign isn't set anywhere, so this hasn't been checking anything for a while... */ 1369 if (bc.dwBufferBytes & pStreamDS->uAlign) 1370 DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n", 1371 bc.dwBufferBytes, pStreamDS->uAlign + 1)); 1372 #endif 1373 LogFlow(("returns S_OK\n")); 1374 return S_OK; 1375 } 1376 LogRelMax(64, ("DSound: Getting capture buffer capabilities for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1377 } 1378 else 1379 LogRelMax(64, ("DSound: Getting capture format for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1380 1381 IDirectSoundCaptureBuffer8_Release(pStreamDS->In.pDSCB); 1382 pStreamDS->In.pDSCB = NULL; 1383 LogFlowFunc(("returns %Rhrc\n", hrc)); 1384 return hrc; 1385 } 1386 1387 1388 /** 1389 * Worker for drvHostDSoundHA_StreamCreate that creates playback stream. 1390 * 1391 * @returns Windows COM status code. 1392 * @param pThis The DSound instance data. 1393 * @param pStreamDS The stream instance data. 1394 * @param pCfgReq The requested stream config (input). 1395 * @param pCfgAcq Where to return the actual stream config. This is a 1396 * copy of @a *pCfgReq when called. 1397 * @param pWaveFmtX On input the requested stream format. 1398 * Updated to the actual stream format on successful 1399 * return. 1400 */ 1401 static HRESULT drvHostDSoundStreamCreatePlayback(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, 1402 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, WAVEFORMATEX *pWaveFmtX) 1403 { 1404 Assert(pStreamDS->Out.pDSB == NULL); 1405 HRESULT hrc; 1406 1407 /* 1408 * Create, initialize and set up a DirectSound8 instance the first time 1409 * we go thru here. 1410 */ 1411 /** @todo bird: Or should we rather just throw this away after we've gotten the 1412 * sound buffer? Old code would just leak it... */ 1413 if (pThis->pDS == NULL) 1414 { 1415 hrc = drvHostDSoundCreateDSPlaybackInstance(pThis->Cfg.pGuidPlay, &pThis->pDS); 1416 if (FAILED(hrc)) 1417 return hrc; /* The worker has complained to the release log already. */ 1418 } 1419 1420 /* 1421 * As we reuse our (secondary) buffer for playing out data as it comes in, 1422 * we're using this buffer as a so-called streaming buffer. 1423 * 1424 * See https://msdn.microsoft.com/en-us/library/windows/desktop/ee419014(v=vs.85).aspx 1425 * 1426 * However, as we do not want to use memory on the sound device directly 1427 * (as most modern audio hardware on the host doesn't have this anyway), 1428 * we're *not* going to use DSBCAPS_STATIC for that. 1429 * 1430 * Instead we're specifying DSBCAPS_LOCSOFTWARE, as this fits the bill 1431 * of copying own buffer data to our secondary's Direct Sound buffer. 1432 */ 1433 DSBUFFERDESC BufferDesc = 1434 { 1435 /*.dwSize = */ sizeof(BufferDesc), 1436 /*.dwFlags = */ DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE, 1437 /*.dwBufferBytes = */ PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize), 1438 /*.dwReserved = */ 0, 1439 /*.lpwfxFormat = */ pWaveFmtX 1440 /*.guid3DAlgorithm = {0, 0, 0, {0,0,0,0, 0,0,0,0}} */ 1441 }; 1442 LogRel2(("DSound: Requested playback buffer is %#x B / %u B / %RU64 ms\n", BufferDesc.dwBufferBytes, BufferDesc.dwBufferBytes, 1443 PDMAudioPropsBytesToMilli(&pCfgReq->Props, BufferDesc.dwBufferBytes))); 1444 1445 LPDIRECTSOUNDBUFFER pLegacyDSB = NULL; 1446 hrc = IDirectSound8_CreateSoundBuffer(pThis->pDS, &BufferDesc, &pLegacyDSB, NULL); 1447 if (FAILED(hrc)) 1448 { 1449 LogRelMax(64, ("DSound: Creating playback sound buffer for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1450 return hrc; 1451 } 1452 1453 /* Get the IDirectSoundBuffer8 version of the interface. */ 1454 hrc = IDirectSoundBuffer_QueryInterface(pLegacyDSB, IID_IDirectSoundBuffer8, (PVOID *)&pStreamDS->Out.pDSB); 1455 IDirectSoundBuffer_Release(pLegacyDSB); 1456 if (FAILED(hrc)) 1457 { 1458 LogRelMax(64, ("DSound: Querying IID_IDirectSoundBuffer8 for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1459 return hrc; 1460 } 1461 1462 /* 1463 * Query the actual stream parameters, they may differ from what we requested. 1464 */ 1465 RT_ZERO(*pWaveFmtX); 1466 hrc = IDirectSoundBuffer8_GetFormat(pStreamDS->Out.pDSB, pWaveFmtX, sizeof(*pWaveFmtX), NULL); 1467 if (SUCCEEDED(hrc)) 1468 { 1469 /** @todo r=bird: We aren't converting/checking the pWaveFmtX content... */ 1470 1471 DSBCAPS BufferCaps = { /*.dwSize = */ sizeof(BufferCaps), 0, 0, 0, 0 }; 1472 hrc = IDirectSoundBuffer8_GetCaps(pStreamDS->Out.pDSB, &BufferCaps); 1473 if (SUCCEEDED(hrc)) 1474 { 1475 LogRel2(("DSound: Acquired playback buffer capabilities for '%s':\n" 1476 "DSound: dwFlags = %#RX32\n" 1477 "DSound: dwBufferBytes = %#RX32 B / %RU32 B / %RU64 ms\n" 1478 "DSound: dwUnlockTransferRate = %RU32 KB/s\n" 1479 "DSound: dwPlayCpuOverhead = %RU32%%\n", 1480 pCfgReq->szName, BufferCaps.dwFlags, BufferCaps.dwBufferBytes, BufferCaps.dwBufferBytes, 1481 PDMAudioPropsBytesToMilli(&pCfgReq->Props, BufferCaps.dwBufferBytes), 1482 BufferCaps.dwUnlockTransferRate, BufferCaps.dwPlayCpuOverhead)); 1483 1484 /* Update buffer related stuff: */ 1485 pStreamDS->cbBufSize = BufferCaps.dwBufferBytes; 1486 pCfgAcq->Backend.cFramesBufferSize = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, BufferCaps.dwBufferBytes); 1487 pCfgAcq->Backend.cFramesPeriod = pCfgAcq->Backend.cFramesBufferSize / 4; /* total fiction */ 1488 pCfgAcq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesPreBuffering * pCfgAcq->Backend.cFramesBufferSize 1489 / RT_MAX(pCfgReq->Backend.cFramesBufferSize, 1); 1490 1491 /** @todo r=bird: WTF is this for? */ 1492 pThis->pDSStrmOut = pStreamDS; 1493 1494 #if 0 /** @todo r=bird: uAlign isn't set anywhere, so this hasn't been checking anything for a while... */ 1495 if (bc.dwBufferBytes & pStreamDS->uAlign) 1496 DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n", 1497 bc.dwBufferBytes, pStreamDS->uAlign + 1)); 1498 #endif 1499 LogFlow(("returns S_OK\n")); 1500 return S_OK; 1501 } 1502 LogRelMax(64, ("DSound: Getting playback buffer capabilities for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1503 } 1504 else 1505 LogRelMax(64, ("DSound: Getting playback format for '%s' failed: %Rhrc\n", pCfgReq->szName, hrc)); 1506 1507 IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB); 1508 pStreamDS->Out.pDSB = NULL; 1509 LogFlowFunc(("returns %Rhrc\n", hrc)); 1510 return hrc; 1511 } 1512 1513 1514 /** 1515 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 1516 */ 1517 static DECLCALLBACK(int) drvHostDSoundHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1518 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1519 { 1520 PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); 1521 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 1522 AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER); 1523 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 1524 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 1525 AssertReturn(pCfgReq->enmDir == PDMAUDIODIR_IN || pCfgReq->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER); 1526 Assert(PDMAudioStrmCfgEquals(pCfgReq, pCfgAcq)); 1527 1528 const char * const pszStreamType = pCfgReq->enmDir == PDMAUDIODIR_IN ? "capture" : "playback"; RT_NOREF(pszStreamType); 1529 LogFlowFunc(("enmSrc/Dst=%s '%s'\n", 1530 pCfgReq->enmDir == PDMAUDIODIR_IN ? PDMAudioRecSrcGetName(pCfgReq->u.enmSrc) 1531 : PDMAudioPlaybackDstGetName(pCfgReq->u.enmDst), pCfgReq->szName)); 1532 1533 /* For whatever reason: */ 1534 dsoundUpdateStatusInternal(pThis); 1535 1536 /* 1537 * DSound has different COM interfaces for working with input and output 1538 * streams, so we'll quickly part ways here after some common format 1539 * specification setup and logging. 1540 */ 1541 #if defined(RTLOG_REL_ENABLED) || defined(LOG_ENABLED) 1542 char szTmp[64]; 1543 #endif 1544 LogRel2(("DSound: Opening %s stream '%s' (%s)\n", pCfgReq->szName, pszStreamType, 1545 PDMAudioPropsToString(&pCfgReq->Props, szTmp, sizeof(szTmp)))); 1546 1547 WAVEFORMATEX WaveFmtX; 1548 dsoundWaveFmtFromCfg(pCfgReq, &WaveFmtX); 1549 LogRel2(("DSound: Requested %s format for '%s':\n" 1550 "DSound: wFormatTag = %RU16\n" 1551 "DSound: nChannels = %RU16\n" 1552 "DSound: nSamplesPerSec = %RU32\n" 1553 "DSound: nAvgBytesPerSec = %RU32\n" 1554 "DSound: nBlockAlign = %RU16\n" 1555 "DSound: wBitsPerSample = %RU16\n" 1556 "DSound: cbSize = %RU16\n", 1557 pszStreamType, pCfgReq->szName, WaveFmtX.wFormatTag, WaveFmtX.nChannels, WaveFmtX.nSamplesPerSec, 1558 WaveFmtX.nAvgBytesPerSec, WaveFmtX.nBlockAlign, WaveFmtX.wBitsPerSample, WaveFmtX.cbSize)); 1559 1560 HRESULT hrc; 1561 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 1562 hrc = drvHostDSoundStreamCreateCapture(pThis, pStreamDS, pCfgReq, pCfgAcq, &WaveFmtX); 1563 else 1564 hrc = drvHostDSoundStreamCreatePlayback(pThis, pStreamDS, pCfgReq, pCfgAcq, &WaveFmtX); 1565 int rc; 1566 if (SUCCEEDED(hrc)) 1567 { 1568 LogRel2(("DSound: Acquired %s format for '%s':\n" 1569 "DSound: wFormatTag = %RU16\n" 1570 "DSound: nChannels = %RU16\n" 1571 "DSound: nSamplesPerSec = %RU32\n" 1572 "DSound: nAvgBytesPerSec = %RU32\n" 1573 "DSound: nBlockAlign = %RU16\n" 1574 "DSound: wBitsPerSample = %RU16\n" 1575 "DSound: cbSize = %RU16\n", 1576 pszStreamType, pCfgReq->szName, WaveFmtX.wFormatTag, WaveFmtX.nChannels, WaveFmtX.nSamplesPerSec, 1577 WaveFmtX.nAvgBytesPerSec, WaveFmtX.nBlockAlign, WaveFmtX.wBitsPerSample, WaveFmtX.cbSize)); 1578 1579 /* 1580 * Copy the acquired config and reset the stream (clears the buffer). 1581 */ 1582 PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq); 1583 drvHostDSoundStreamReset(pThis, pStreamDS); 1584 rc = VINF_SUCCESS; 1585 } 1586 else 1587 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 1588 1589 LogFlowFunc(("returns %Rrc\n", rc)); 1590 return rc; 1591 } 1592 1593 1594 static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1595 { 1596 AssertPtrReturn(pThis, E_POINTER); 1597 AssertPtrReturn(pStreamDS, E_POINTER); 1598 1599 LogFlowFuncEnter(); 1600 1601 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 1602 if (SUCCEEDED(hr)) 1603 { 1604 DSLOG(("DSound: Closing playback stream\n")); 1605 RTCritSectEnter(&pThis->CritSect); 1606 1607 if (pStreamDS->Out.pDSB) 1608 { 1609 IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB); 1610 pStreamDS->Out.pDSB = NULL; 1611 } 1612 1613 pThis->pDSStrmOut = NULL; 1614 1615 RTCritSectLeave(&pThis->CritSect); 1616 } 1617 1618 if (FAILED(hr)) 1619 DSLOGREL(("DSound: Stopping playback stream %p failed with %Rhrc\n", pStreamDS, hr)); 1620 1621 return hr; 1622 } 1623 1624 1625 static int dsoundDestroyStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1626 { 1627 LogFlowFuncEnter(); 1628 1629 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 1630 if (SUCCEEDED(hr)) 1631 { 1632 hr = directSoundPlayClose(pThis, pStreamDS); 1633 if (FAILED(hr)) 1634 return VERR_GENERAL_FAILURE; /** @todo Fix. */ 1635 } 1636 1637 return VINF_SUCCESS; 1638 } 1639 1640 1292 1641 static HRESULT directSoundCaptureClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1293 1642 { … … 1315 1664 1316 1665 1317 static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, 1318 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1319 { 1320 AssertPtrReturn(pThis, E_POINTER); 1321 AssertPtrReturn(pStreamDS, E_POINTER); 1322 AssertPtrReturn(pCfgReq, E_POINTER); 1323 AssertPtrReturn(pCfgAcq, E_POINTER); 1324 1325 /** @todo r=bird: I cannot see any code populating pCfgAcq... */ 1326 1666 static int dsoundDestroyStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1667 { 1327 1668 LogFlowFuncEnter(); 1328 1669 1329 Assert(pStreamDS->In.pDSCB == NULL); 1330 1331 DSLOG(("DSound: Opening capturing stream (uHz=%RU32, cChannels=%RU8, cBits=%u, fSigned=%RTbool)\n", pCfgReq->Props.uHz, 1332 PDMAudioPropsChannels(&pCfgReq->Props), PDMAudioPropsSampleBits(&pCfgReq->Props), pCfgReq->Props.fSigned)); 1333 1334 WAVEFORMATEX wfx; 1335 int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx); 1336 if (RT_FAILURE(rc)) 1337 return E_INVALIDARG; 1338 1339 /** @todo r=bird: Why is this called every time? It triggers a device 1340 * enumeration. Andy claimed on IRC that enumeration was only done once... */ 1341 dsoundUpdateStatusInternal(pThis); 1342 1343 HRESULT hr = directSoundCaptureInterfaceCreate(pThis->Cfg.pGuidCapture, &pThis->pDSC); 1344 if (FAILED(hr)) 1345 return hr; 1346 1347 do /* For readability breaks... */ 1348 { 1349 DSCBUFFERDESC bd; 1350 RT_ZERO(bd); 1351 1352 bd.dwSize = sizeof(bd); 1353 bd.lpwfxFormat = &wfx; 1354 bd.dwBufferBytes = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize); 1355 1356 DSLOG(("DSound: Requested capture buffer is %RU64ms (%ld bytes)\n", 1357 PDMAudioPropsBytesToMilli(&pCfgReq->Props, bd.dwBufferBytes), bd.dwBufferBytes)); 1358 1359 LPDIRECTSOUNDCAPTUREBUFFER pDSCB; 1360 hr = IDirectSoundCapture_CreateCaptureBuffer(pThis->pDSC, &bd, &pDSCB, NULL); 1361 if (FAILED(hr)) 1362 { 1363 if (hr == E_ACCESSDENIED) 1364 { 1365 DSLOGREL(("DSound: Capturing input from host not possible, access denied\n")); 1366 } 1367 else 1368 DSLOGREL(("DSound: Creating capture buffer failed with %Rhrc\n", hr)); 1369 break; 1370 } 1371 1372 hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pStreamDS->In.pDSCB); 1373 IDirectSoundCaptureBuffer_Release(pDSCB); 1374 if (FAILED(hr)) 1375 { 1376 DSLOGREL(("DSound: Querying interface for capture buffer failed with %Rhrc\n", hr)); 1377 break; 1378 } 1379 1380 /* 1381 * Query the actual parameters. 1382 */ 1383 DWORD offByteReadPos = 0; 1384 hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pStreamDS->In.pDSCB, NULL, &offByteReadPos); 1385 if (FAILED(hr)) 1386 { 1387 offByteReadPos = 0; 1388 DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr)); 1389 } 1390 1391 RT_ZERO(wfx); 1392 hr = IDirectSoundCaptureBuffer8_GetFormat(pStreamDS->In.pDSCB, &wfx, sizeof(wfx), NULL); 1393 if (FAILED(hr)) 1394 { 1395 DSLOGREL(("DSound: Getting capture format failed with %Rhrc\n", hr)); 1396 break; 1397 } 1398 1399 DSCBCAPS bc; 1400 RT_ZERO(bc); 1401 bc.dwSize = sizeof(bc); 1402 hr = IDirectSoundCaptureBuffer8_GetCaps(pStreamDS->In.pDSCB, &bc); 1403 if (FAILED(hr)) 1404 { 1405 DSLOGREL(("DSound: Getting capture capabilities failed with %Rhrc\n", hr)); 1406 break; 1407 } 1408 1409 DSLOG(("DSound: Acquired capture buffer is %RU64ms (%ld bytes)\n", 1410 PDMAudioPropsBytesToMilli(&pCfgReq->Props, bc.dwBufferBytes), bc.dwBufferBytes)); 1411 1412 DSLOG(("DSound: Capture format:\n" 1413 " dwBufferBytes = %RI32\n" 1414 " dwFlags = 0x%x\n" 1415 " wFormatTag = %RI16\n" 1416 " nChannels = %RI16\n" 1417 " nSamplesPerSec = %RU32\n" 1418 " nAvgBytesPerSec = %RU32\n" 1419 " nBlockAlign = %RI16\n" 1420 " wBitsPerSample = %RI16\n" 1421 " cbSize = %RI16\n", 1422 bc.dwBufferBytes, 1423 bc.dwFlags, 1424 wfx.wFormatTag, 1425 wfx.nChannels, 1426 wfx.nSamplesPerSec, 1427 wfx.nAvgBytesPerSec, 1428 wfx.nBlockAlign, 1429 wfx.wBitsPerSample, 1430 wfx.cbSize)); 1431 1432 if (bc.dwBufferBytes & pStreamDS->uAlign) 1433 DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n", 1434 bc.dwBufferBytes, pStreamDS->uAlign + 1)); 1435 1436 /* Initial state: reading at the initial capture position, no error. */ 1437 pStreamDS->In.offReadPos = 0; 1438 pStreamDS->cbBufSize = bc.dwBufferBytes; 1439 1440 pThis->pDSStrmIn = pStreamDS; 1441 1442 pCfgAcq->Backend.cFramesBufferSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize); 1443 1444 } while (0); 1445 1446 if (FAILED(hr)) 1447 directSoundCaptureClose(pThis, pStreamDS); 1448 1449 LogFlowFunc(("Returning %Rhrc\n", hr)); 1450 return hr; 1451 } 1452 1453 1454 static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1455 { 1456 AssertPtrReturn(pThis, E_POINTER); 1457 AssertPtrReturn(pStreamDS, E_POINTER); 1458 1459 LogFlowFuncEnter(); 1460 1461 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 1462 if (SUCCEEDED(hr)) 1463 { 1464 DSLOG(("DSound: Closing playback stream\n")); 1465 RTCritSectEnter(&pThis->CritSect); 1466 1467 if (pStreamDS->Out.pDSB) 1468 { 1469 IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB); 1470 pStreamDS->Out.pDSB = NULL; 1471 } 1472 1473 pThis->pDSStrmOut = NULL; 1474 1475 RTCritSectLeave(&pThis->CritSect); 1476 } 1477 1478 if (FAILED(hr)) 1479 DSLOGREL(("DSound: Stopping playback stream %p failed with %Rhrc\n", pStreamDS, hr)); 1480 1481 return hr; 1482 } 1483 1484 1485 static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, 1486 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1487 { 1488 AssertPtrReturn(pThis, E_POINTER); 1489 AssertPtrReturn(pStreamDS, E_POINTER); 1490 AssertPtrReturn(pCfgReq, E_POINTER); 1491 AssertPtrReturn(pCfgAcq, E_POINTER); 1492 LogFlowFuncEnter(); 1493 1494 Assert(pStreamDS->Out.pDSB == NULL); 1495 1496 DSLOG(("DSound: Opening playback stream (uHz=%RU32, cChannels=%RU8, cBits=%u, fSigned=%RTbool)\n", pCfgReq->Props.uHz, 1497 PDMAudioPropsChannels(&pCfgReq->Props), PDMAudioPropsSampleBits(&pCfgReq->Props), pCfgReq->Props.fSigned)); 1498 1499 WAVEFORMATEX wfx; 1500 int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx); 1501 if (RT_FAILURE(rc)) 1502 return E_INVALIDARG; 1503 1504 DSLOG(("DSound: Requested playback format:\n" 1505 " wFormatTag = %RI16\n" 1506 " nChannels = %RI16\n" 1507 " nSamplesPerSec = %RU32\n" 1508 " nAvgBytesPerSec = %RU32\n" 1509 " nBlockAlign = %RI16\n" 1510 " wBitsPerSample = %RI16\n" 1511 " cbSize = %RI16\n", 1512 wfx.wFormatTag, 1513 wfx.nChannels, 1514 wfx.nSamplesPerSec, 1515 wfx.nAvgBytesPerSec, 1516 wfx.nBlockAlign, 1517 wfx.wBitsPerSample, 1518 wfx.cbSize)); 1519 1520 /* Waste some time: */ 1521 dsoundUpdateStatusInternal(pThis); 1522 1523 HRESULT hr = directSoundPlayInterfaceCreate(pThis->Cfg.pGuidPlay, &pThis->pDS); 1524 if (FAILED(hr)) 1525 return hr; 1526 1527 do /* To use breaks. */ 1528 { 1529 LPDIRECTSOUNDBUFFER pDSB = NULL; 1530 1531 DSBUFFERDESC bd; 1532 RT_ZERO(bd); 1533 bd.dwSize = sizeof(bd); 1534 bd.lpwfxFormat = &wfx; 1535 1536 /* 1537 * As we reuse our (secondary) buffer for playing out data as it comes in, 1538 * we're using this buffer as a so-called streaming buffer. 1539 * 1540 * See https://msdn.microsoft.com/en-us/library/windows/desktop/ee419014(v=vs.85).aspx 1541 * 1542 * However, as we do not want to use memory on the sound device directly 1543 * (as most modern audio hardware on the host doesn't have this anyway), 1544 * we're *not* going to use DSBCAPS_STATIC for that. 1545 * 1546 * Instead we're specifying DSBCAPS_LOCSOFTWARE, as this fits the bill 1547 * of copying own buffer data to our secondary's Direct Sound buffer. 1548 */ 1549 bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE; 1550 bd.dwBufferBytes = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize); 1551 1552 DSLOG(("DSound: Requested playback buffer is %RU64ms (%ld bytes)\n", 1553 PDMAudioPropsBytesToMilli(&pCfgReq->Props, bd.dwBufferBytes), bd.dwBufferBytes)); 1554 1555 hr = IDirectSound8_CreateSoundBuffer(pThis->pDS, &bd, &pDSB, NULL); 1556 if (FAILED(hr)) 1557 { 1558 DSLOGREL(("DSound: Creating playback sound buffer failed with %Rhrc\n", hr)); 1559 break; 1560 } 1561 1562 /* "Upgrade" to IDirectSoundBuffer8 interface. */ 1563 hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (PVOID *)&pStreamDS->Out.pDSB); 1564 IDirectSoundBuffer_Release(pDSB); 1565 if (FAILED(hr)) 1566 { 1567 DSLOGREL(("DSound: Querying playback sound buffer interface failed with %Rhrc\n", hr)); 1568 break; 1569 } 1570 1571 /* 1572 * Query the actual parameters set for this stream. 1573 * Those might be different than the initially requested parameters. 1574 */ 1575 RT_ZERO(wfx); 1576 hr = IDirectSoundBuffer8_GetFormat(pStreamDS->Out.pDSB, &wfx, sizeof(wfx), NULL); 1577 if (FAILED(hr)) 1578 { 1579 DSLOGREL(("DSound: Getting playback format failed with %Rhrc\n", hr)); 1580 break; 1581 } 1582 1583 DSBCAPS bc; 1584 RT_ZERO(bc); 1585 bc.dwSize = sizeof(bc); 1586 1587 hr = IDirectSoundBuffer8_GetCaps(pStreamDS->Out.pDSB, &bc); 1588 if (FAILED(hr)) 1589 { 1590 DSLOGREL(("DSound: Getting playback capabilities failed with %Rhrc\n", hr)); 1591 break; 1592 } 1593 1594 DSLOG(("DSound: Acquired playback buffer is %RU64ms (%ld bytes)\n", 1595 PDMAudioPropsBytesToMilli(&pCfgReq->Props, bc.dwBufferBytes), bc.dwBufferBytes)); 1596 1597 DSLOG(("DSound: Acquired playback format:\n" 1598 " dwBufferBytes = %RI32\n" 1599 " dwFlags = 0x%x\n" 1600 " wFormatTag = %RI16\n" 1601 " nChannels = %RI16\n" 1602 " nSamplesPerSec = %RU32\n" 1603 " nAvgBytesPerSec = %RU32\n" 1604 " nBlockAlign = %RI16\n" 1605 " wBitsPerSample = %RI16\n" 1606 " cbSize = %RI16\n", 1607 bc.dwBufferBytes, 1608 bc.dwFlags, 1609 wfx.wFormatTag, 1610 wfx.nChannels, 1611 wfx.nSamplesPerSec, 1612 wfx.nAvgBytesPerSec, 1613 wfx.nBlockAlign, 1614 wfx.wBitsPerSample, 1615 wfx.cbSize)); 1616 1617 if (bc.dwBufferBytes & pStreamDS->uAlign) 1618 DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n", 1619 bc.dwBufferBytes, pStreamDS->uAlign + 1)); 1620 1621 /* 1622 * Initial state. 1623 * dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct 1624 * playback buffer position. 1625 */ 1626 pStreamDS->cbBufSize = bc.dwBufferBytes; 1627 1628 pThis->pDSStrmOut = pStreamDS; 1629 1630 const uint32_t cfBufSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize); 1631 1632 pCfgAcq->Backend.cFramesBufferSize = cfBufSize; 1633 pCfgAcq->Backend.cFramesPeriod = cfBufSize / 4; 1634 pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod * 2; 1635 1636 } while (0); 1637 1638 if (FAILED(hr)) 1639 directSoundPlayClose(pThis, pStreamDS); 1640 1641 return hr; 1642 } 1643 1644 1645 static void dsoundPlayClearBuffer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1646 { 1647 AssertPtrReturnVoid(pStreamDS); 1648 1649 PPDMAUDIOPCMPROPS pProps = &pStreamDS->Cfg.Props; 1650 1651 HRESULT hr = IDirectSoundBuffer_SetCurrentPosition(pStreamDS->Out.pDSB, 0 /* Position */); 1652 if (FAILED(hr)) 1653 DSLOGREL(("DSound: Setting current position to 0 when clearing buffer failed with %Rhrc\n", hr)); 1654 1655 PVOID pv1; 1656 hr = directSoundPlayLock(pThis, pStreamDS, 1657 0 /* dwOffset */, pStreamDS->cbBufSize, 1658 &pv1, NULL, 0, 0, DSBLOCK_ENTIREBUFFER); 1659 if (SUCCEEDED(hr)) 1660 { 1661 PDMAudioPropsClearBuffer(pProps, pv1, pStreamDS->cbBufSize, PDMAUDIOPCMPROPS_B2F(pProps, pStreamDS->cbBufSize)); 1662 1663 directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, NULL, 0, 0); 1664 1665 /* Make sure to get the last playback position and current write position from DirectSound again. 1666 * Those positions in theory could have changed, re-fetch them to be sure. */ 1667 DWORD offPlay = 0; 1668 DWORD offWrite = 0; 1669 hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlay, &offWrite); 1670 if (SUCCEEDED(hr)) 1671 { 1672 pStreamDS->Out.offPlayCursorLastPlayed = offPlay; 1673 pStreamDS->Out.offWritePos = offWrite; 1674 } 1675 else 1676 DSLOGREL(("DSound: Re-fetching current position when clearing buffer failed with %Rhrc\n", hr)); 1677 } 1678 } 1679 1680 1681 static int dsoundCreateStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, 1682 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1683 { 1684 LogFlowFunc(("pStreamDS=%p, pCfgReq=%p\n", pStreamDS, pCfgReq)); 1685 1686 int rc; 1687 1688 /* Try to open playback in case the device is already there. */ 1689 HRESULT hr = directSoundPlayOpen(pThis, pStreamDS, pCfgReq, pCfgAcq); 1690 if (SUCCEEDED(hr)) 1691 { 1692 rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq); 1693 if (RT_SUCCESS(rc)) 1694 dsoundStreamReset(pThis, pStreamDS); 1695 } 1696 else 1697 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 1698 1699 LogFlowFuncLeaveRC(rc); 1700 return rc; 1701 } 1702 1703 1704 static int dsoundCreateStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, 1705 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1706 { 1707 LogFunc(("pStreamDS=%p, pCfgReq=%p, enmRecSource=%s\n", 1708 pStreamDS, pCfgReq, PDMAudioRecSrcGetName(pCfgReq->u.enmSrc))); 1709 1710 1711 /* Try to open capture in case the device is already there. */ 1712 int rc; 1713 HRESULT hr = directSoundCaptureOpen(pThis, pStreamDS, pCfgReq, pCfgAcq); 1714 if (SUCCEEDED(hr)) 1715 { 1716 rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq); 1717 if (RT_SUCCESS(rc)) 1718 dsoundStreamReset(pThis, pStreamDS); 1719 } 1720 else 1721 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 1722 1723 return rc; 1724 } 1725 1726 1727 /** 1728 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 1729 */ 1730 static DECLCALLBACK(int) drvHostDSoundHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1731 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1732 { 1733 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1734 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1735 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 1736 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 1737 1738 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface); 1670 directSoundCaptureClose(pThis, pStreamDS); 1671 1672 return VINF_SUCCESS; 1673 } 1674 1675 1676 /** 1677 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 1678 */ 1679 static DECLCALLBACK(int) drvHostDSoundHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 1680 { 1681 PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); 1739 1682 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 1740 1741 int rc; 1742 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 1743 rc = dsoundCreateStreamIn(pThis, pStreamDS, pCfgReq, pCfgAcq); 1744 else 1745 rc = dsoundCreateStreamOut(pThis, pStreamDS, pCfgReq, pCfgAcq); 1746 1747 if (RT_SUCCESS(rc)) 1748 { 1749 /** @todo already copied */ 1750 rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq); 1751 if (RT_SUCCESS(rc)) 1752 rc = RTCritSectInit(&pStreamDS->CritSect); 1753 } 1754 1755 return rc; 1756 } 1757 1758 1759 static int dsoundDestroyStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1760 { 1761 LogFlowFuncEnter(); 1762 1763 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 1764 if (SUCCEEDED(hr)) 1765 { 1766 hr = directSoundPlayClose(pThis, pStreamDS); 1767 if (FAILED(hr)) 1768 return VERR_GENERAL_FAILURE; /** @todo Fix. */ 1769 } 1770 1771 return VINF_SUCCESS; 1772 } 1773 1774 1775 static int dsoundDestroyStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS) 1776 { 1777 LogFlowFuncEnter(); 1778 1779 directSoundCaptureClose(pThis, pStreamDS); 1780 1781 return VINF_SUCCESS; 1782 } 1783 1784 1785 /** 1786 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 1787 */ 1788 static DECLCALLBACK(int) drvHostDSoundHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 1789 { 1790 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1791 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1792 1793 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface); 1794 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 1683 AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER); 1795 1684 1796 1685 int rc; … … 1827 1716 1828 1717 if (fEnable) 1829 d soundStreamReset(pThis, pStreamDS);1718 drvHostDSoundStreamReset(pThis, pStreamDS); 1830 1719 1831 1720 pStreamDS->fEnabled = fEnable; … … 1885 1774 { 1886 1775 if (fFlush) 1887 d soundStreamReset(pThis, pStreamDS);1776 drvHostDSoundStreamReset(pThis, pStreamDS); 1888 1777 } 1889 1778 … … 2046 1935 { 2047 1936 if (fFlush) 2048 d soundStreamReset(pThis, pStreamDS);1937 drvHostDSoundStreamReset(pThis, pStreamDS); 2049 1938 } 2050 1939 … … 2077 1966 if (SUCCEEDED(hr)) 2078 1967 { 1968 /** @todo r=bird: This isn't working. CfgAcq isn't initialized! */ 2079 1969 PDMAUDIOSTREAMCFG CfgAcq; 2080 hr = directSoundCaptureOpen(pThis, pStreamDS, &pStreamDS->Cfg /* pCfgReq */, &CfgAcq); 1970 WAVEFORMATEX WaveFmtX; 1971 dsoundWaveFmtFromCfg(&pStreamDS->Cfg, &WaveFmtX); 1972 hr = drvHostDSoundStreamCreateCapture(pThis, pStreamDS, &pStreamDS->Cfg, &CfgAcq, &WaveFmtX); 2081 1973 if (SUCCEEDED(hr)) 2082 1974 { 2083 rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, &CfgAcq); 2084 if (RT_FAILURE(rc)) 2085 break; 1975 PDMAudioStrmCfgCopy(&pStreamDS->Cfg, &CfgAcq); 2086 1976 2087 1977 /** @todo What to do if the format has changed? */ … … 2128 2018 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd) 2129 2019 { 2130 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2131 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2132 2133 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface); 2020 PDRVHOSTDSOUND pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); 2134 2021 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2022 AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER); 2135 2023 2136 2024 int rc;
Note:
See TracChangeset
for help on using the changeset viewer.