Changeset 70916 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Feb 8, 2018 3:53:53 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp
r70888 r70916 70 70 } while (0) 71 71 72 73 72 /** Maximum number of attempts to restore the sound buffer before giving up. */ 74 73 #define DRV_DSOUND_RESTORE_ATTEMPTS_MAX 3 74 /** Default input latency (in ms). */ 75 #define DRV_DSOUND_DEFAULT_LATENCY_MS_IN 50 76 /** Default output latency (in ms). */ 77 #define DRV_DSOUND_DEFAULT_LATENCY_MS_OUT 50 75 78 76 79 /** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */ … … 90 93 typedef FNDIRECTSOUNDCAPTURECREATE8 *PFNDIRECTSOUNDCAPTURECREATE8; 91 94 92 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 93 # define VBOX_DSOUND_MAX_EVENTS 3 95 #define VBOX_DSOUND_MAX_EVENTS 3 94 96 95 97 typedef enum DSOUNDEVENT … … 98 100 DSOUNDEVENT_INPUT, 99 101 DSOUNDEVENT_OUTPUT, 100 } DSOUNDEVENT; 101 #endif /* VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS */ 102 } DSOUNDEVENT; 102 103 103 104 typedef struct DSOUNDHOSTCFG 104 105 { 105 DWORD cbBufferIn;106 DWORD cbBufferOut;107 RTUUID uuidPlay;108 LPCGUID pGuidPlay;109 RTUUID uuidCapture;110 LPCGUID pGuidCapture;106 unsigned int msLatencyIn; 107 unsigned int msLatencyOut; 108 RTUUID uuidPlay; 109 LPCGUID pGuidPlay; 110 RTUUID uuidCapture; 111 LPCGUID pGuidCapture; 111 112 } DSOUNDHOSTCFG, *PDSOUNDHOSTCFG; 112 113 … … 119 120 /** Whether this stream is in an enable state on the DirectSound side. */ 120 121 bool fEnabled; 122 RTCRITSECT CritSect; 121 123 union 122 124 { … … 148 150 DWORD cbBufSize; 149 151 /** Flag indicating whether playback was (re)started. */ 150 bool fRestartPlayback; 152 bool fFirstPlayback; 153 uint64_t tsLastPlayMs; 154 bool fPendingPlayback; 155 bool fPendingClose; 156 PRTCIRCBUF pCircBuf; 151 157 } Out; 152 158 }; … … 166 172 RTLISTANCHOR lstDevOutput; 167 173 /** DirectSound configuration options. */ 168 DSOUNDHOSTCFG cfg;174 DSOUNDHOSTCFG Cfg; 169 175 /** Whether this backend supports any audio input. */ 170 176 bool fEnabledIn; … … 183 189 PFNPDMHOSTAUDIOCALLBACK pfnCallback; 184 190 #endif 185 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS186 /** Pointer to the audio connector interface of the driver/device above us. */187 PPDMIAUDIOCONNECTOR pUpIAudioConnector;188 191 /** Stopped indicator. */ 189 192 bool fStopped; … … 194 197 /** Array of events to wait for in notification thread. */ 195 198 HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS]; 196 /** Number of events to wait for in notification thread.197 * Must not exceed VBOX_DSOUND_MAX_EVENTS. */198 uint8_t cEvents;199 199 /** Pointer to the input stream. */ 200 200 PDSOUNDSTREAM pDSStrmIn; 201 201 /** Pointer to the output stream. */ 202 202 PDSOUNDSTREAM pDSStrmOut; 203 #endif204 203 } DRVHOSTDSOUND, *PDRVHOSTDSOUND; 205 204 … … 236 235 *********************************************************************************************************************************/ 237 236 static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB); 237 static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush); 238 238 static HRESULT directSoundCaptureStop(PDSOUNDSTREAM pStreamDS); 239 239 240 240 static void dsoundDeviceRemove(PDSOUNDDEV pDev); 241 241 static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg); 242 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 242 243 243 static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown); 244 #endif 244 245 245 static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis); 246 246 static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum); … … 401 401 HRESULT hr = IDirectSoundBuffer8_Restore(pDSB); 402 402 if (FAILED(hr)) 403 DSLOG(("DSound: Restoring playback buffer\n")); 404 else 403 405 DSLOGREL(("DSound: Restoring playback buffer failed with %Rhrc\n", hr)); 406 404 407 return hr; 405 408 } … … 435 438 DWORD dwFlags) 436 439 { 440 AssertReturn(dwBytes, VERR_INVALID_PARAMETER); 441 437 442 HRESULT hr = E_FAIL; 438 443 AssertCompile(DRV_DSOUND_RESTORE_ATTEMPTS_MAX > 0); … … 470 475 } 471 476 472 DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc \n", hr));477 DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc (dwOff=%ld, dwBytes=%ld)\n", hr, dwOffset, dwBytes)); 473 478 return hr; 474 479 } … … 543 548 else 544 549 { 545 hr = IDirectSound8_Initialize(pThis->pDS, pThis-> cfg.pGuidPlay);550 hr = IDirectSound8_Initialize(pThis->pDS, pThis->Cfg.pGuidPlay); 546 551 if (SUCCEEDED(hr)) 547 552 { … … 573 578 AssertPtrReturn(pStreamDS, E_POINTER); 574 579 575 HRESULT hr = S_OK; 576 577 if (pStreamDS->Out.pDSB) 578 { 579 DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pStreamDS, pStreamDS->Out.pDSB)); 580 581 hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB); 582 if (SUCCEEDED(hr)) 583 { 584 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 585 if (pThis->aEvents[DSOUNDEVENT_OUTPUT] != NULL) 586 { 587 CloseHandle(pThis->aEvents[DSOUNDEVENT_OUTPUT]); 588 pThis->aEvents[DSOUNDEVENT_OUTPUT] = NULL; 589 590 if (pThis->cEvents) 591 pThis->cEvents--; 592 593 pThis->pDSStrmOut = NULL; 594 } 595 596 int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */); 597 AssertRC(rc2); 598 #endif 580 LogFlowFuncEnter(); 581 582 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 583 if (FAILED(hr)) 584 return hr; 585 586 DSLOG(("DSound: Closing playback stream\n")); 587 588 if (pStreamDS->Out.pCircBuf) 589 Assert(RTCircBufUsed(pStreamDS->Out.pCircBuf) == 0); 590 591 if (SUCCEEDED(hr)) 592 { 593 RTCritSectEnter(&pThis->CritSect); 594 595 if (pStreamDS->Out.pCircBuf) 596 { 597 RTCircBufDestroy(pStreamDS->Out.pCircBuf); 598 pStreamDS->Out.pCircBuf = NULL; 599 } 600 601 if (pStreamDS->Out.pDSB) 602 { 599 603 IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB); 600 604 pStreamDS->Out.pDSB = NULL; 601 605 } 606 607 pThis->pDSStrmOut = NULL; 608 609 RTCritSectLeave(&pThis->CritSect); 610 611 int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */); 612 AssertRC(rc2); 602 613 } 603 614 … … 617 628 AssertPtrReturn(pCfgAcq, E_POINTER); 618 629 619 DSLOG(("DSound: Opening playback stream %p: cbBufferOut=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n", 620 pStreamDS, 621 pThis->cfg.cbBufferOut, 630 LogFlowFuncEnter(); 631 632 Assert(pStreamDS->Out.pDSB == NULL); 633 634 DSLOG(("DSound: Opening playback stream (uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool)\n", 622 635 pCfgReq->Props.uHz, 623 636 pCfgReq->Props.cChannels, 624 637 pCfgReq->Props.cBits, 625 638 pCfgReq->Props.fSigned)); 626 627 if (pStreamDS->Out.pDSB != NULL)628 {629 /* Should not happen but be forgiving. */630 DSLOGREL(("DSound: Playback buffer already exists\n"));631 directSoundPlayClose(pThis, pStreamDS);632 }633 639 634 640 WAVEFORMATEX wfx; … … 682 688 */ 683 689 bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE; 684 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS685 690 bd.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; 686 #endif 687 bd.dwBufferBytes = pThis->cfg.cbBufferOut; 691 692 bd.dwBufferBytes = DrvAudioHlpCalcBitrate(&pCfgReq->Props) / 8; 693 694 DSLOG(("DSound: Playback buffer is %ld bytes\n", bd.dwBufferBytes)); 688 695 689 696 hr = IDirectSound8_CreateSoundBuffer(pThis->pDS, &bd, &pDSB, NULL); … … 750 757 bc.dwBufferBytes, pStreamDS->uAlign + 1)); 751 758 752 if (bc.dwBufferBytes != pThis->cfg.cbBufferOut)753 DSLOGREL(("DSound: Playback buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",754 bc.dwBufferBytes, pThis->cfg.cbBufferOut));755 756 759 /* 757 760 * Initial state. … … 760 763 */ 761 764 pStreamDS->Out.cbBufSize = bc.dwBufferBytes; 762 DSLOG(("DSound: cMaxSamplesInBuffer=%RU32\n", pStreamDS->Out.cbBufSize)); 763 764 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 765 766 RTCritSectEnter(&pThis->CritSect); 767 768 rc = RTCircBufCreate(&pStreamDS->Out.pCircBuf, pStreamDS->Out.cbBufSize); 769 AssertRC(rc); 770 765 771 /* 766 772 * Install notification. 767 773 */ 768 pThis->aEvents[DSOUNDEVENT_OUTPUT] = CreateEvent(NULL /* Security attribute */,769 FALSE /* bManualReset */, FALSE /* bInitialState */,770 NULL /* lpName */);771 if (pThis->aEvents[DSOUNDEVENT_OUTPUT] == NULL)772 {773 hr = HRESULT_FROM_WIN32(GetLastError());774 DSLOGREL(("DSound: CreateEvent for output failed with %Rhrc\n", hr));775 break;776 }777 778 774 LPDIRECTSOUNDNOTIFY8 pNotify; 779 775 hr = IDirectSoundNotify_QueryInterface(pStreamDS->Out.pDSB, IID_IDirectSoundNotify8, (PVOID *)&pNotify); 780 776 if (SUCCEEDED(hr)) 781 777 { 782 DSBPOSITIONNOTIFY dsBufPosNotify; 783 RT_ZERO(dsBufPosNotify); 784 dsBufPosNotify.dwOffset = DSBPN_OFFSETSTOP; 785 dsBufPosNotify.hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT]; 786 787 hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 1 /* Count */, &dsBufPosNotify); 778 DSBPOSITIONNOTIFY dsPosNotify[3]; 779 RT_ZERO(dsPosNotify); 780 781 dsPosNotify[0].dwOffset = 0; 782 dsPosNotify[0].hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT]; 783 784 dsPosNotify[1].dwOffset = float(pStreamDS->Out.cbBufSize * 0.3); 785 dsPosNotify[1].hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT]; 786 787 dsPosNotify[2].dwOffset = float(pStreamDS->Out.cbBufSize * 0.6); 788 dsPosNotify[2].hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT]; 789 790 hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 3 /* Count */, dsPosNotify); 788 791 if (FAILED(hr)) 789 792 DSLOGREL(("DSound: Setting playback position notification failed with %Rhrc\n", hr)); 790 793 791 794 IDirectSoundNotify_Release(pNotify); 795 796 pThis->pDSStrmOut = pStreamDS; 792 797 } 793 798 else 794 799 DSLOGREL(("DSound: Querying interface for position notification failed with %Rhrc\n", hr)); 795 800 796 if (FAILED(hr)) 797 break; 798 799 pThis->pDSStrmOut = pStreamDS; 800 801 Assert(pThis->cEvents < VBOX_DSOUND_MAX_EVENTS); 802 pThis->cEvents++; 803 804 /* Let the thread know. */ 805 dsoundNotifyThread(pThis, false /* fShutdown */); 806 807 /* Trigger the just installed output notification. */ 808 hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, 0); 809 if (FAILED(hr)) 810 break; 811 812 #endif /* VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS */ 813 814 pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pThis->cfg.cbBufferOut); 801 RTCritSectLeave(&pThis->CritSect); 802 803 pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->Out.cbBufSize); 815 804 816 805 } while (0); … … 889 878 890 879 891 static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS )880 static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush) 892 881 { 893 882 AssertPtrReturn(pThis, E_POINTER); … … 900 889 if (pStreamDS->fEnabled) 901 890 { 902 DSLOG(("DSound: Stopping playback\n"));891 DSLOG(("DSound: %s playback\n", fFlush ? "Stopping" : "Pausing")); 903 892 904 893 hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB); … … 910 899 } 911 900 912 if (SUCCEEDED(hr)) 913 pStreamDS->fEnabled = false; 914 } 901 pStreamDS->fEnabled = false; 902 } 903 } 904 905 if (SUCCEEDED(hr)) 906 { 907 if (fFlush) 908 RTCircBufReset(pStreamDS->Out.pCircBuf); 915 909 } 916 910 917 911 if (FAILED(hr)) 918 DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));912 DSLOGREL(("DSound: %s playback failed with %Rhrc\n", fFlush ? "Stopping" : "Pausing", hr)); 919 913 920 914 return hr; … … 927 921 AssertPtrReturn(pStreamDS, E_POINTER); 928 922 929 HRESULT hr; 930 if (pStreamDS->Out.pDSB != NULL) 931 { 932 DWORD dwStatus; 933 hr = directSoundPlayGetStatus(pThis, pStreamDS->Out.pDSB, &dwStatus); 934 if (SUCCEEDED(hr)) 935 { 936 if (dwStatus & DSBSTATUS_PLAYING) 937 { 938 DSLOG(("DSound: Already playing\n")); 939 } 940 else 941 { 942 dsoundPlayClearBuffer(pThis, pStreamDS); 943 944 pStreamDS->Out.fRestartPlayback = true; 945 pStreamDS->fEnabled = true; 946 947 DSLOG(("DSound: Playback started\n")); 948 949 /* 950 * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlay, 951 * because it is necessary to put some samples into the buffer first. 952 */ 953 } 954 } 955 } 956 else 957 hr = E_UNEXPECTED; 958 959 if (FAILED(hr)) 960 DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr)); 961 962 return hr; 923 Assert(pStreamDS->fEnabled == false); 924 925 pStreamDS->Out.fFirstPlayback = true; 926 pStreamDS->fEnabled = true; 927 928 DSLOG(("DSound: Playback started\n")); 929 930 return S_OK; 963 931 } 964 932 … … 974 942 int rc = VINF_SUCCESS; 975 943 976 LPCGUID pGUID = pThis-> cfg.pGuidCapture;944 LPCGUID pGUID = pThis->Cfg.pGuidCapture; 977 945 if (!pGUID) 978 946 { … … 1105 1073 AssertPtrReturn(pStreamDS, E_POINTER); 1106 1074 1075 LogFlowFuncEnter(); 1076 1107 1077 HRESULT hr = S_OK; 1108 1078 … … 1110 1080 && pStreamDS->In.pDSCB) 1111 1081 { 1112 DSLOG(("DSound: Closing capturing stream %p, buffer %p\n", pStreamDS, pStreamDS->In.pDSCB));1082 DSLOG(("DSound: Closing capturing stream\n")); 1113 1083 1114 1084 hr = directSoundCaptureStop(pStreamDS); … … 1135 1105 AssertPtrReturn(pCfgAcq, E_POINTER); 1136 1106 1137 DSLOG(("DSound: Opening capturing stream %p: cbBufferIn=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n", 1138 pStreamDS, 1139 pThis->cfg.cbBufferIn, 1107 LogFlowFuncEnter(); 1108 1109 Assert(pStreamDS->In.pDSCB == NULL); 1110 1111 DSLOG(("DSound: Opening capturing stream (uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool)\n", 1140 1112 pCfgReq->Props.uHz, 1141 1113 pCfgReq->Props.cChannels, … … 1143 1115 pCfgReq->Props.fSigned)); 1144 1116 1145 if (pStreamDS->In.pDSCB != NULL)1146 {1147 /* Should not happen but be forgiving. */1148 DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));1149 directSoundCaptureClose(pStreamDS);1150 }1151 1152 1117 WAVEFORMATEX wfx; 1153 1118 int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx); … … 1163 1128 do /* To use breaks. */ 1164 1129 { 1165 LPDIRECTSOUNDCAPTUREBUFFER pDSCB = NULL;1166 1167 1130 DSCBUFFERDESC bd; 1168 1131 RT_ZERO(bd); … … 1170 1133 bd.dwSize = sizeof(bd); 1171 1134 bd.lpwfxFormat = &wfx; 1172 bd.dwBufferBytes = pThis->cfg.cbBufferIn; 1173 1135 bd.dwBufferBytes = DrvAudioHlpCalcBitrate(&pCfgReq->Props) / 8; 1136 1137 DSLOG(("DSound: Capture buffer is %ld bytes\n", bd.dwBufferBytes)); 1138 1139 LPDIRECTSOUNDCAPTUREBUFFER pDSCB; 1174 1140 hr = IDirectSoundCapture_CreateCaptureBuffer(pThis->pDSC, &bd, &pDSCB, NULL); 1175 1141 if (FAILED(hr)) … … 1217 1183 if (FAILED(hr)) 1218 1184 { 1219 DSLOGREL((" Getting capture capabilities failed with %Rhrc\n", hr));1185 DSLOGREL(("DSound: Getting capture capabilities failed with %Rhrc\n", hr)); 1220 1186 break; 1221 1187 } … … 1245 1211 bc.dwBufferBytes, pStreamDS->uAlign + 1)); 1246 1212 1247 if (bc.dwBufferBytes != pThis->cfg.cbBufferIn)1248 DSLOGREL(("DSound: Capture buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",1249 bc.dwBufferBytes, pThis->cfg.cbBufferIn));1250 1251 1213 /* Initial state: reading at the initial capture position, no error. */ 1252 pStreamDS->In.offReadPos = offByteReadPos; 1253 pStreamDS->In.cbBufSize = bc.dwBufferBytes; 1254 1255 pStreamDS->In.hrLastCapture = S_OK; 1256 1257 DSLOG(("DSound: Opened capturing offReadPos=%RU32, cbBufSize=%RU32\n", 1258 pStreamDS->In.offReadPos, pStreamDS->In.cbBufSize)); 1259 1260 pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pThis->cfg.cbBufferIn); 1214 pStreamDS->In.offReadPos = offByteReadPos; 1215 pStreamDS->In.cbBufSize = bc.dwBufferBytes; 1216 pStreamDS->In.hrLastCapture = S_OK; 1217 1218 pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, bc.dwBufferBytes); 1261 1219 1262 1220 } while (0); … … 1317 1275 else 1318 1276 { 1319 DWORD fFlags = 0; 1320 #ifndef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 1321 fFlags |= DSCBSTART_LOOPING; 1322 #endif 1277 const DWORD fFlags = DSCBSTART_LOOPING; 1278 1323 1279 DSLOG(("DSound: Starting to capture\n")); 1324 1280 hr = IDirectSoundCaptureBuffer8_Start(pStreamDS->In.pDSCB, fFlags); … … 1526 1482 if (RT_SUCCESS(rc)) 1527 1483 { 1528 #if def VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS1484 #if 0 1529 1485 if ( pThis->fEnabledOut != RT_BOOL(cbCtx.cDevOut) 1530 1486 || pThis->fEnabledIn != RT_BOOL(cbCtx.cDevIn)) … … 1533 1489 * let the connector know that something has changed within the host backend. */ 1534 1490 } 1535 #e lse1491 #endif 1536 1492 pThis->fEnabledOut = RT_BOOL(cbCtx.cDevOut); 1537 1493 pThis->fEnabledIn = RT_BOOL(cbCtx.cDevIn); 1538 #endif1539 1494 1540 1495 Cfg.cMaxStreamsIn = UINT32_MAX; … … 1565 1520 pStreamDS->Out.offPlayCursorLastPending = 0; 1566 1521 pStreamDS->Out.cbWritten = 0; 1567 pStreamDS->Out.fRestartPlayback = true; 1522 pStreamDS->Out.fFirstPlayback = true; 1523 pStreamDS->Out.fPendingPlayback = false; 1524 pStreamDS->Out.tsLastPlayMs = 0; 1568 1525 pStreamDS->Out.cbBufSize = 0; 1569 1526 … … 1589 1546 { 1590 1547 case PDMAUDIOSTREAMCMD_ENABLE: 1591 case PDMAUDIOSTREAMCMD_RESUME:1592 1548 { 1593 1549 hr = directSoundPlayStart(pThis, pStreamDS); 1594 1550 if (FAILED(hr)) 1551 rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */ 1552 break; 1553 } 1554 1555 case PDMAUDIOSTREAMCMD_RESUME: 1556 { 1557 hr = directSoundPlayStart(pThis, pStreamDS); 1558 if (SUCCEEDED(hr)) 1595 1559 { 1596 hr = directSoundPlayClose(pThis, pStreamDS); 1597 if (SUCCEEDED(hr)) 1598 { 1599 PDMAUDIOSTREAMCFG CfgAcq; 1600 hr = directSoundPlayOpen(pThis, pStreamDS, pStreamDS->pCfg /* pCfqReq */, &CfgAcq); 1601 if (SUCCEEDED(hr)) 1602 { 1603 DrvAudioHlpStreamCfgFree(pStreamDS->pCfg); 1604 1605 pStreamDS->pCfg = DrvAudioHlpStreamCfgDup(&CfgAcq); 1606 AssertPtr(pStreamDS->pCfg); 1607 1608 /** @todo What to do if the format has changed? */ 1609 } 1610 } 1611 if (SUCCEEDED(hr)) 1612 hr = directSoundPlayStart(pThis, pStreamDS); 1560 BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_OUTPUT]); 1561 Assert(fRc); 1613 1562 } 1614 1563 1564 if (FAILED(hr)) 1565 rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */ 1566 break; 1567 } 1568 1569 case PDMAUDIOSTREAMCMD_DISABLE: 1570 case PDMAUDIOSTREAMCMD_PAUSE: 1571 { 1572 hr = directSoundPlayStop(pThis, pStreamDS, enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE /* fFlush */); 1615 1573 if (FAILED(hr)) 1616 1574 rc = VERR_NOT_SUPPORTED; … … 1618 1576 } 1619 1577 1620 case PDMAUDIOSTREAMCMD_DISABLE:1621 case PDMAUDIOSTREAMCMD_PAUSE:1622 {1623 AssertPtr(pThis->pDS);1624 1625 hr = directSoundPlayStop(pThis, pStreamDS);1626 if (FAILED(hr))1627 rc = VERR_NOT_SUPPORTED;1628 break;1629 }1630 1631 1578 default: 1632 1579 { … … 1640 1587 return rc; 1641 1588 } 1642 1643 1589 1644 1590 /** … … 1661 1607 uint32_t cbWrittenTotal = 0; 1662 1608 1663 #ifdef DEBUG_andy 1664 LogFlowFuncEnter(); 1665 #endif 1666 1667 do /* to use 'break' */ 1668 { 1669 AssertPtr(pStreamDS->pCfg); 1670 PPDMAUDIOPCMPROPS pProps = &pStreamDS->pCfg->Props; 1671 1672 DWORD cbFree; 1673 rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree); 1674 if (RT_FAILURE(rc)) 1675 break; 1676 1677 if (pStreamDS->Out.fRestartPlayback == false) 1678 { 1679 DWORD offPlayCursor, offWriteCursor; 1680 HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor); 1681 if (SUCCEEDED(hr)) 1682 { 1683 uint32_t cbPending; 1684 if (pStreamDS->Out.offPlayCursorLastPlayed <= offPlayCursor) 1685 cbPending = offPlayCursor - pStreamDS->Out.offPlayCursorLastPlayed; 1686 else 1687 cbPending = pStreamDS->Out.cbBufSize - pStreamDS->Out.offPlayCursorLastPlayed + offPlayCursor; 1688 1689 pStreamDS->Out.cbWritten -= RT_MIN(pStreamDS->Out.cbWritten, cbPending); 1690 pStreamDS->Out.offPlayCursorLastPlayed = offPlayCursor; 1691 } 1692 } 1693 1694 /* 1695 * Check for full buffer, do not allow the offPlayWritePos to catch cbPlayPos during playback, 1696 * i.e. always leave a free space for 1 audio sample. 1697 */ 1698 const DWORD cbSample = PDMAUDIOPCMPROPS_F2B(pProps, 1); 1699 if (cbFree < cbSample) 1700 break; 1701 Assert(cbFree >= cbSample); 1702 cbFree -= cbSample; 1703 1704 uint32_t cbLive = cxBuf; 1705 1706 /* Do not write more than available space in the DirectSound playback buffer. */ 1707 cbLive = RT_MIN(cbFree, cbLive); 1708 cbLive &= ~pStreamDS->uAlign; 1709 1710 if (!cbLive) 1711 break; 1712 1713 LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB; 1714 AssertPtr(pDSB); 1715 1716 PVOID pv1, pv2; 1717 DWORD cb1, cb2; 1718 HRESULT hr = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, cbLive, 1719 &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */); 1720 if (FAILED(hr)) 1721 { 1722 rc = VERR_ACCESS_DENIED; 1723 break; 1724 } 1725 1726 AssertPtr(pv1); 1727 Assert(cb1); 1728 1729 memcpy(pv1, pvBuf, cb1); 1730 cbWrittenTotal = cb1; 1731 1732 if (pv2 && cb2) /* Buffer wrap-around? Write second part. */ 1733 { 1734 memcpy(pv2, (uint8_t *)pvBuf + cb1, cb2); 1735 cbWrittenTotal += cb2; 1736 } 1737 1738 Assert(cbLive == cb1 + cb2); 1739 1740 directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2); 1741 1742 pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cbWrittenTotal) % pStreamDS->Out.cbBufSize; 1743 pStreamDS->Out.cbWritten += cbWrittenTotal; 1744 1745 DSLOGF(("DSound: %RU32/%RU32, buffer write pos %ld, rc=%Rrc\n", 1746 cbWrittenTotal, cbLive, pStreamDS->Out.offWritePos, rc)); 1747 1748 if (pStreamDS->Out.fRestartPlayback) 1749 { 1750 /* 1751 * The playback has been just started. 1752 * Some samples of the new sound have been copied to the buffer 1753 * and it can start playing. 1754 */ 1755 pStreamDS->Out.fRestartPlayback = false; 1756 1757 DWORD fFlags = 0; 1758 #ifndef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 1759 fFlags |= DSCBSTART_LOOPING; 1760 #endif 1761 for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++) 1762 { 1763 hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, fFlags); 1764 if ( SUCCEEDED(hr) 1765 || hr != DSERR_BUFFERLOST) 1766 break; 1767 else 1768 { 1769 LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n")); 1770 directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 1771 } 1772 } 1773 1774 if (FAILED(hr)) 1775 { 1776 DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr)); 1777 rc = VERR_NOT_SUPPORTED; 1778 break; 1779 } 1780 } 1781 1782 } while (0); 1609 uint8_t *pbBuf = (uint8_t *)pvBuf; 1610 PRTCIRCBUF pCircBuf = pStreamDS->Out.pCircBuf; 1611 1612 uint32_t cbToPlay = RT_MIN(cxBuf, (uint32_t)RTCircBufFree(pCircBuf)); 1613 while (cbToPlay) 1614 { 1615 void *pvChunk; 1616 size_t cbChunk; 1617 RTCircBufAcquireWriteBlock(pCircBuf, cbToPlay, &pvChunk, &cbChunk); 1618 1619 if (cbChunk) 1620 { 1621 memcpy(pvChunk, pbBuf, cbChunk); 1622 1623 pbBuf += cbChunk; 1624 Assert(cbToPlay >= cbChunk); 1625 cbToPlay -= (uint32_t)cbChunk; 1626 1627 cbWrittenTotal += (uint32_t)cbChunk; 1628 } 1629 1630 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 1631 } 1632 1633 Assert(cbWrittenTotal <= cxBuf); 1634 1635 if ( pStreamDS->Out.fFirstPlayback 1636 && RTCircBufUsed(pCircBuf)) 1637 { 1638 BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_OUTPUT]); 1639 Assert(fRc); 1640 1641 // Log3Func(("cxBuf=%RU32, cbWrittenTotal=%RU32, %RU64ms\n", cxBuf, cbWrittenTotal, tsNow - s_lastplayed)); 1642 } 1783 1643 1784 1644 if (RT_SUCCESS(rc)) … … 1798 1658 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 1799 1659 1800 directSoundPlayClose(pThis, pStreamDS); 1660 LogFlowFuncEnter(); 1661 1662 HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */); 1663 if (SUCCEEDED(hr)) 1664 { 1665 hr = directSoundPlayClose(pThis, pStreamDS); 1666 if (FAILED(hr)) 1667 return VERR_GENERAL_FAILURE; /** @todo Fix. */ 1668 } 1801 1669 1802 1670 return VINF_SUCCESS; … … 2010 1878 static int dsoundDestroyStreamIn(PDSOUNDSTREAM pStreamDS) 2011 1879 { 1880 LogFlowFuncEnter(); 1881 2012 1882 directSoundCaptureClose(pStreamDS); 2013 1883 … … 2030 1900 return VINF_SUCCESS; 2031 1901 } 2032 2033 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS2034 1902 2035 1903 static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown) … … 2051 1919 2052 1920 2053 static DECLCALLBACK(int) dsound NotificationThread(RTTHREAD hThreadSelf, void *pvUser)1921 static DECLCALLBACK(int) dsoundThread(RTTHREAD hThreadSelf, void *pvUser) 2054 1922 { 2055 1923 PDRVHOSTDSOUND pThis = (PDRVHOSTDSOUND)pvUser; … … 2062 1930 AssertRC(rc); 2063 1931 2064 do 2065 { 1932 for (;;) 1933 { 1934 RTCritSectEnter(&pThis->CritSect); 1935 2066 1936 HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS]; 2067 1937 DWORD cEvents = 0; … … 2073 1943 Assert(cEvents); 2074 1944 2075 LogFlowFunc(("Waiting: cEvents=%ld\n", cEvents));1945 RTCritSectLeave(&pThis->CritSect); 2076 1946 2077 1947 DWORD dwObj = WaitForMultipleObjects(cEvents, aEvents, FALSE /* bWaitAll */, INFINITE); 1948 1949 RTCritSectEnter(&pThis->CritSect); 1950 2078 1951 switch (dwObj) 2079 1952 { … … 2090 1963 } 2091 1964 2092 default: 1965 case WAIT_OBJECT_0: 1966 case WAIT_OBJECT_0 + 1: 1967 case WAIT_OBJECT_0 + 2: 1968 case WAIT_OBJECT_0 + 3: 1969 case WAIT_OBJECT_0 + 4: 2093 1970 { 2094 dwObj = WAIT_OBJECT_0 + cEvents - 1; 2095 if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_NOTIFY]) 1971 dwObj -= WAIT_OBJECT_0; 1972 1973 Log3Func(("Event %ld\n", dwObj)); 1974 1975 PDSOUNDSTREAM pStreamDS = pThis->pDSStrmOut; 1976 1977 if (! pStreamDS 1978 || !pStreamDS->fEnabled) 1979 break; 1980 1981 if (dwObj == DSOUNDEVENT_NOTIFY) 2096 1982 { 2097 LogFlowFunc(("Notify\n"));2098 1983 } 2099 else if ( aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_INPUT])1984 else if (dwObj == DSOUNDEVENT_INPUT) 2100 1985 { 2101 2102 1986 } 2103 else if ( aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_OUTPUT])1987 else if (dwObj == DSOUNDEVENT_OUTPUT) 2104 1988 { 2105 DWORD cbFree; 2106 rc = dsoundGetFreeOut(pThis->pDSStream, &cbFree); 2107 if ( RT_SUCCESS(rc) 2108 && cbFree) 1989 LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB; 1990 if (!pDSB) 1991 break; 1992 1993 HRESULT hr; 1994 1995 DWORD offPlayCursor; DWORD offWriteCursor2; 1996 hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor2); 1997 1998 //Log3Func(("p=%ld, w=%ld\n", offPlayCursor, offWriteCursor2)); 1999 2000 DWORD cbFree, cbRemaining; 2001 if (pStreamDS->Out.fFirstPlayback) 2109 2002 { 2110 PDMAUDIOCBDATA_DATA_OUTPUT Out; 2111 Out.cbInFree = cbFree; 2112 Out.cbOutWritten = 0; 2113 2114 while (!Out.cbOutWritten) 2003 DWORD offWriteCursor; 2004 hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, NULL, &offWriteCursor); 2005 if (FAILED(hr)) 2006 break; 2007 2008 pStreamDS->Out.offWritePos = offWriteCursor; 2009 2010 cbFree = pStreamDS->Out.cbBufSize; 2011 cbRemaining = pStreamDS->Out.cbBufSize; 2012 } 2013 else 2014 { 2015 DWORD offPlayCursor; 2016 hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, NULL); 2017 if (FAILED(hr)) 2018 break; 2019 2020 cbFree = dsoundRingDistance(offPlayCursor, pStreamDS->Out.offWritePos, pStreamDS->Out.cbBufSize); 2021 cbRemaining = dsoundRingDistance(pStreamDS->Out.offWritePos, offPlayCursor, pStreamDS->Out.cbBufSize); 2022 } 2023 2024 PRTCIRCBUF pCircBuf = pStreamDS->Out.pCircBuf; 2025 AssertPtr(pCircBuf); 2026 2027 DWORD cbUsed = (uint32_t)RTCircBufUsed(pCircBuf); 2028 DWORD cbToPlay = RT_MIN(cbFree, cbUsed); 2029 2030 //Log3Func(("cbUsed=%ld, cbToPlay=%ld\n", cbUsed, cbToPlay)); 2031 2032 while (cbToPlay) 2033 { 2034 void *pvBuf; 2035 size_t cbBuf; 2036 RTCircBufAcquireReadBlock(pCircBuf, cbToPlay, &pvBuf, &cbBuf); 2037 2038 if (cbBuf) 2115 2039 { 2116 rc = pThis->pUpIAudioConnector->pfnCallback(pThis->pUpIAudioConnector, 2117 PDMAUDIOCALLBACKTYPE_OUTPUT, &Out, sizeof(Out)); 2118 if (RT_FAILURE(rc)) 2040 PVOID pv1, pv2; 2041 DWORD cb1, cb2; 2042 hr = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, (DWORD)cbBuf, 2043 &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */); 2044 if (FAILED(hr)) 2119 2045 break; 2120 RTThreadSleep(100); 2046 2047 AssertPtr(pv1); 2048 Assert(cb1); 2049 2050 memcpy(pv1, pvBuf, cb1); 2051 2052 if (pv2 && cb2) /* Buffer wrap-around? Write second part. */ 2053 memcpy(pv2, (uint8_t *)pvBuf + cb1, cb2); 2054 2055 directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2); 2056 2057 pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->Out.cbBufSize; 2058 2059 Assert(cbToPlay >= cbBuf); 2060 cbToPlay -= (uint32_t)cbBuf; 2061 2062 pStreamDS->Out.cbWritten += cb1 + cb2; 2121 2063 } 2122 2064 2123 LogFlowFunc(("Output: cbBuffer=%ld, cbFree=%ld, cbWritten=%RU32, rc=%Rrc\n", 2124 cbBuffer, cbFree, Out.cbOutWritten, rc)); 2065 RTCircBufReleaseReadBlock(pCircBuf, cbBuf); 2066 } 2067 2068 if (pStreamDS->Out.fFirstPlayback) 2069 { 2070 DWORD fFlags = DSCBSTART_LOOPING; 2071 2072 for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++) 2073 { 2074 hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, fFlags); 2075 if ( SUCCEEDED(hr) 2076 || hr != DSERR_BUFFERLOST) 2077 break; 2078 else 2079 { 2080 LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n")); 2081 directSoundPlayRestore(pThis, pStreamDS->Out.pDSB); 2082 } 2083 } 2084 2085 if (SUCCEEDED(hr)) 2086 { 2087 DSLOG(("DSound: Started playing output\n")); 2088 pStreamDS->Out.fFirstPlayback = false; 2089 pStreamDS->Out.fPendingPlayback = true; 2090 } 2091 } 2092 else /* Continue playback */ 2093 { 2094 if ( !RTCircBufUsed(pCircBuf) 2095 && !cbRemaining) 2096 { 2097 DSLOG(("DSound: Stopping playing output\n")); 2098 hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB); 2099 } 2125 2100 } 2126 2101 } 2127 2102 break; 2128 2103 } 2129 } 2104 2105 default: 2106 AssertFailed(); 2107 break; 2108 } 2109 2110 RTCritSectLeave(&pThis->CritSect); 2130 2111 2131 2112 if (pThis->fShutdown) 2132 2113 break; 2133 2114 2134 } while (RT_SUCCESS(rc));2115 } /* for */ 2135 2116 2136 2117 pThis->fStopped = true; … … 2140 2121 } 2141 2122 2142 #endif /* VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS */2143 2144 2145 2123 /** 2146 2124 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown} … … 2152 2130 LogFlowFuncEnter(); 2153 2131 2154 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS2155 2132 int rc = dsoundNotifyThread(pThis, true /* fShutdown */); 2156 2133 AssertRC(rc); … … 2162 2139 Assert(pThis->fStopped); 2163 2140 2164 if (pThis->aEvents[DSOUNDEVENT_NOTIFY]) 2165 { 2166 CloseHandle(pThis->aEvents[DSOUNDEVENT_NOTIFY]); 2167 pThis->aEvents[DSOUNDEVENT_NOTIFY] = NULL; 2168 } 2169 #else 2170 RT_NOREF_PV(pThis); 2171 #endif 2141 for (int i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++) 2142 { 2143 if (pThis->aEvents[i]) 2144 CloseHandle(pThis->aEvents[i]); 2145 } 2172 2146 2173 2147 LogFlowFuncLeave(); … … 2192 2166 IDirectSound_Release(pDirectSound); 2193 2167 2194 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS 2195 /* Create notification event. */ 2196 pThis->aEvents[DSOUNDEVENT_NOTIFY] = CreateEvent(NULL /* Security attribute */, 2197 FALSE /* bManualReset */, FALSE /* bInitialState */, 2198 NULL /* lpName */); 2199 Assert(pThis->aEvents[DSOUNDEVENT_NOTIFY] != NULL); 2168 /* Create notification events. */ 2169 for (int i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++) 2170 { 2171 pThis->aEvents[i] = CreateEvent(NULL /* Security attribute */, 2172 FALSE /* bManualReset */, FALSE /* bInitialState */, 2173 NULL /* lpName */); 2174 Assert(pThis->aEvents[i] != NULL); 2175 } 2200 2176 2201 2177 /* Start notification thread. */ 2202 rc = RTThreadCreate(&pThis->Thread, dsound NotificationThread,2178 rc = RTThreadCreate(&pThis->Thread, dsoundThread, 2203 2179 pThis /*pvUser*/, 0 /*cbStack*/, 2204 2180 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dsoundNtfy"); … … 2210 2186 DSLOGREL(("DSound: Waiting for thread to initialize failed with rc=%Rrc\n", rc)); 2211 2187 } 2212 else2188 else 2213 2189 DSLOGREL(("DSound: Creating thread failed with rc=%Rrc\n", rc)); 2214 #else2215 rc = VINF_SUCCESS;2216 #endif2217 2190 2218 2191 dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, DSOUNDENUMCBFLAGS_LOG /* fEnum */); … … 2252 2225 static int dsoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg) 2253 2226 { 2254 unsigned int uBufsizeOut, uBufsizeIn; 2255 2256 CFGMR3QueryUIntDef(pCfg, "BufsizeOut", &uBufsizeOut, _16K); 2257 CFGMR3QueryUIntDef(pCfg, "BufsizeIn", &uBufsizeIn, _16K); 2258 pThis->cfg.cbBufferOut = uBufsizeOut; 2259 pThis->cfg.cbBufferIn = uBufsizeIn; 2260 2261 pThis->cfg.pGuidPlay = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->cfg.uuidPlay); 2262 pThis->cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn", &pThis->cfg.uuidCapture); 2263 2264 DSLOG(("DSound: Configuration cbBufferIn=%ld, cbBufferOut=%ld, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n", 2265 pThis->cfg.cbBufferIn, 2266 pThis->cfg.cbBufferOut, 2267 &pThis->cfg.uuidPlay, 2268 &pThis->cfg.uuidCapture)); 2227 CFGMR3QueryUIntDef(pCfg, "LatencyMsIn", &pThis->Cfg.msLatencyIn, DRV_DSOUND_DEFAULT_LATENCY_MS_IN); 2228 CFGMR3QueryUIntDef(pCfg, "LatencyMsOut", &pThis->Cfg.msLatencyOut, DRV_DSOUND_DEFAULT_LATENCY_MS_OUT); 2229 2230 pThis->Cfg.pGuidPlay = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->Cfg.uuidPlay); 2231 pThis->Cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn", &pThis->Cfg.uuidCapture); 2232 2233 DSLOG(("DSound: Configuration: Input latency = %ums, Output latency = %ums, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n", 2234 pThis->Cfg.msLatencyIn, 2235 pThis->Cfg.msLatencyOut, 2236 &pThis->Cfg.uuidPlay, 2237 &pThis->Cfg.uuidCapture)); 2269 2238 2270 2239 return VINF_SUCCESS; … … 2395 2364 AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAG_NONE); 2396 2365 2397 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);2398 2366 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2399 2367 2400 2368 if (pStreamDS->fEnabled) 2401 { 2402 DWORD cbFree; 2403 int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree); 2404 if ( RT_SUCCESS(rc) 2405 && cbFree) 2406 { 2407 Log3Func(("cbFree=%ld\n", cbFree)); 2408 return (uint32_t)cbFree; 2409 } 2410 } 2369 return (uint32_t)RTCircBufFree(pStreamDS->Out.pCircBuf); 2411 2370 2412 2371 return 0; … … 2422 2381 AssertPtrReturn(pStream, 0); 2423 2382 2424 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);2425 2383 PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream; 2426 2384 2427 2385 if (pStreamDS->pCfg->enmDir == PDMAUDIODIR_OUT) 2428 2386 { 2429 DWORD dwStatus; 2430 HRESULT hr = directSoundPlayGetStatus(pThis, pStreamDS->Out.pDSB, &dwStatus); 2431 if (hr != DS_OK) 2432 return 0; 2433 2434 if (!(dwStatus & DSBSTATUS_PLAYING)) 2435 return 0; 2436 2437 DWORD offPlayCursor, offWriteCursor; 2438 hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor); 2439 if (SUCCEEDED(hr)) 2440 { 2441 uint32_t cbPending; 2442 if (pStreamDS->Out.offPlayCursorLastPending <= offPlayCursor) 2443 cbPending = offPlayCursor - pStreamDS->Out.offPlayCursorLastPending; 2444 else 2445 cbPending = pStreamDS->Out.cbBufSize - pStreamDS->Out.offPlayCursorLastPending + offPlayCursor; 2446 2447 pStreamDS->Out.cbWritten -= RT_MIN(pStreamDS->Out.cbWritten, cbPending); 2448 pStreamDS->Out.offPlayCursorLastPending = offPlayCursor; 2449 2450 LogFunc(("offPlayCursor=%RU32, offWriteCursor=%RU32\n", offPlayCursor, offWriteCursor)); 2451 LogFunc(("offPlayWritePos=%RU32, cbWritten=%RU64, cbPending=%RU32\n", 2452 pStreamDS->Out.offWritePos, pStreamDS->Out.cbWritten, cbPending)); 2453 2454 /* 2455 * As we operate a DirectSound secondary *streaming* buffer which loops over 2456 * the data repeatedly until stopped, we have to make at least an estimate when we're actually 2457 * done playing the written data on the host. 2458 */ 2459 return pStreamDS->Out.cbWritten; 2460 } 2461 else 2462 LogFunc(("Failed with %Rhrc\n", hr)); 2387 uint32_t cbPending = 0; 2388 2389 /* Any uncommitted data left? */ 2390 if (pStreamDS->Out.pCircBuf) 2391 cbPending = (uint32_t)RTCircBufUsed(pStreamDS->Out.pCircBuf); 2392 2393 /* Check if we have committed data which still needs to be played by 2394 * by DirectSound's streaming buffer. */ 2395 if (!cbPending) 2396 { 2397 const uint64_t tsNowMs = RTTimeMilliTS(); 2398 if (pStreamDS->Out.tsLastPlayMs == 0) 2399 pStreamDS->Out.tsLastPlayMs = tsNowMs; 2400 2401 const uint64_t diffLastPlayMs = tsNowMs - pStreamDS->Out.tsLastPlayMs; 2402 const uint64_t msThreshold = 100; 2403 2404 Log3Func(("diffLastPlayMs=%RU64ms\n", diffLastPlayMs)); 2405 2406 cbPending = (diffLastPlayMs >= msThreshold) ? 0 : 1; 2407 2408 //if (!cbPending) 2409 // directSoundPlayStop(pThis, pStreamDS, false /* fFlush */); 2410 } 2411 2412 return cbPending; 2463 2413 } 2464 2414 /* Note: For input streams we never have pending data left. */ … … 2504 2454 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2505 2455 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2506 2507 LogFlowFuncEnter();2508 2456 2509 2457 /* Nothing to do here for DSound. */ … … 2641 2589 #ifdef VBOX_WITH_AUDIO_CALLBACKS 2642 2590 /* This backend supports host audio callbacks. */ 2643 pThis->IHostAudio.pfnSetCallback 2591 pThis->IHostAudio.pfnSetCallback = drvHostDSoundSetCallback; 2644 2592 pThis->pfnCallback = NULL; 2645 #endif2646 2647 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS2648 /*2649 * Get the IAudioConnector interface of the above driver/device.2650 */2651 pThis->pUpIAudioConnector = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);2652 if (!pThis->pUpIAudioConnector)2653 {2654 AssertMsgFailed(("Configuration error: No audio connector interface above!\n"));2655 return VERR_PDM_MISSING_INTERFACE_ABOVE;2656 }2657 2593 #endif 2658 2594 … … 2665 2601 pThis->fEnabledIn = false; 2666 2602 pThis->fEnabledOut = false; 2667 #ifdef VBOX_WITH_AUDIO_DSOUND_NOTIFICATIONS2668 2603 pThis->fStopped = false; 2669 2604 pThis->fShutdown = false; 2670 2605 2671 2606 RT_ZERO(pThis->aEvents); 2672 pThis->cEvents = 0;2673 #endif2674 2607 2675 2608 int rc = VINF_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.