VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp@ 57625

Last change on this file since 57625 was 57538, checked in by vboxsync, 9 years ago

Typo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.3 KB
Line 
1/* $Id: DrvHostDSound.cpp 57538 2015-08-25 13:51:04Z vboxsync $ */
2/** @file
3 * Windows host backend driver using DirectSound.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 */
19#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
20#include <VBox/log.h>
21#include <dsound.h>
22
23#include <iprt/alloc.h>
24#include <iprt/uuid.h>
25
26#include "AudioMixBuffer.h"
27#include "DrvAudio.h"
28#include "VBoxDD.h"
29
30typedef struct DSOUNDHOSTCFG
31{
32 DWORD cbBufferIn;
33 DWORD cbBufferOut;
34 RTUUID uuidPlay;
35 LPCGUID pGuidPlay;
36 RTUUID uuidCapture;
37 LPCGUID pGuidCapture;
38} DSOUNDHOSTCFG, *PDSOUNDHOSTCFG;
39
40typedef struct DRVHOSTDSOUND
41{
42 /** Pointer to the driver instance structure. */
43 PPDMDRVINS pDrvIns;
44 /** Pointer to host audio interface. */
45 PDMIHOSTAUDIO IHostAudio;
46 /** List of found host input devices. */
47 RTLISTANCHOR lstDevInput;
48 /** List of found host output devices. */
49 RTLISTANCHOR lstDevOutput;
50 /** DirectSound configuration options. */
51 DSOUNDHOSTCFG cfg;
52} DRVHOSTDSOUND, *PDRVHOSTDSOUND;
53
54typedef struct DSOUNDSTREAMOUT
55{
56 PDMAUDIOHSTSTRMOUT strmOut; /* Always must come first! */
57 LPDIRECTSOUND8 pDS;
58 LPDIRECTSOUNDBUFFER8 pDSB;
59 DWORD cbPlayWritePos;
60 DWORD csPlaybackBufferSize;
61 bool fReinitPlayPos;
62 PDMAUDIOSTREAMCFG streamCfg;
63} DSOUNDSTREAMOUT, *PDSOUNDSTREAMOUT;
64
65typedef struct DSOUNDSTREAMIN
66{
67 PDMAUDIOHSTSTRMIN strmIn; /* Always must come first! */
68 LPDIRECTSOUNDCAPTURE8 pDSC;
69 LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
70 DWORD csCaptureReadPos;
71 DWORD csCaptureBufferSize;
72 HRESULT hrLastCaptureIn;
73 PDMAUDIORECSOURCE enmRecSource;
74 PDMAUDIOSTREAMCFG streamCfg;
75} DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
76
77/**
78 * Callback context for enumeration callbacks
79 */
80typedef struct DSOUNDENUMCBCTX
81{
82 PDRVHOSTDSOUND pDrv;
83 PPDMAUDIOBACKENDCFG pCfg;
84} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
85
86typedef struct DSOUNDDEV
87{
88 RTLISTNODE Node;
89 char *pszName;
90 GUID Guid;
91} DSOUNDDEV, *PDSOUNDDEV;
92
93/** Maximum number of release logging entries. */
94static uint32_t s_cMaxRelLogEntries = 32;
95
96/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
97#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
98 ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
99
100static void dsoundDevRemove(PDSOUNDDEV pDev);
101
102static DWORD dsoundRingDistance(DWORD offEnd, DWORD offBegin, DWORD cSize)
103{
104 return offEnd >= offBegin ? offEnd - offBegin : cSize - offBegin + offEnd;
105}
106
107static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
108{
109 RT_BZERO(pFmt, sizeof(WAVEFORMATEX));
110 pFmt->wFormatTag = WAVE_FORMAT_PCM;
111 pFmt->nChannels = pCfg->cChannels;
112 pFmt->nSamplesPerSec = pCfg->uHz;
113 pFmt->nAvgBytesPerSec = pCfg->uHz << (pCfg->cChannels == 2 ? 1: 0);
114 pFmt->nBlockAlign = 1 << (pCfg->cChannels == 2 ? 1: 0);
115 pFmt->cbSize = 0; /* No extra data specified. */
116
117 switch (pCfg->enmFormat)
118 {
119 case AUD_FMT_S8:
120 case AUD_FMT_U8:
121 pFmt->wBitsPerSample = 8;
122 break;
123
124 case AUD_FMT_S16:
125 case AUD_FMT_U16:
126 pFmt->wBitsPerSample = 16;
127 pFmt->nAvgBytesPerSec <<= 1;
128 pFmt->nBlockAlign <<= 1;
129 break;
130
131 case AUD_FMT_S32:
132 case AUD_FMT_U32:
133 pFmt->wBitsPerSample = 32;
134 pFmt->nAvgBytesPerSec <<= 2;
135 pFmt->nBlockAlign <<= 2;
136 break;
137
138 default:
139 AssertMsgFailed(("Wave format %ld not supported\n", pCfg->enmFormat));
140 return VERR_NOT_SUPPORTED;
141 }
142
143 return VINF_SUCCESS;
144}
145
146static char *dsoundGUIDToUtf8StrA(LPCGUID lpGUID)
147{
148 if (lpGUID)
149 {
150 LPOLESTR lpOLEStr;
151 HRESULT hr = StringFromCLSID(*lpGUID, &lpOLEStr);
152 if (SUCCEEDED(hr))
153 {
154 char *pszGUID;
155 int rc = RTUtf16ToUtf8(lpOLEStr, &pszGUID);
156 CoTaskMemFree(lpOLEStr);
157
158 return RT_SUCCESS(rc) ? pszGUID : NULL;
159 }
160 }
161
162 return RTStrDup("<GUID not found>");
163}
164
165static void dsoundFreeDeviceLists(PDRVHOSTDSOUND pThis)
166{
167 PDSOUNDDEV pDev;
168 while (!RTListIsEmpty(&pThis->lstDevInput))
169 {
170 pDev = RTListGetFirst(&pThis->lstDevInput, DSOUNDDEV, Node);
171 dsoundDevRemove(pDev);
172 }
173
174 while (!RTListIsEmpty(&pThis->lstDevOutput))
175 {
176 pDev = RTListGetFirst(&pThis->lstDevOutput, DSOUNDDEV, Node);
177 dsoundDevRemove(pDev);
178 }
179}
180
181static int dsoundPlayRestore(LPDIRECTSOUNDBUFFER8 pDSB)
182{
183 HRESULT hr = IDirectSoundBuffer8_Restore(pDSB);
184 if (SUCCEEDED(hr))
185 return VINF_SUCCESS;
186
187 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error restoring playback buffer: %Rhrc\n", hr));
188 return VERR_INVALID_STATE;
189}
190
191static int dsoundUnlockOutput(LPDIRECTSOUNDBUFFER8 pDSB,
192 LPVOID pv1, LPVOID pv2,
193 DWORD cb1, DWORD cb2)
194{
195 HRESULT hr = IDirectSoundBuffer8_Unlock(pDSB, pv1, cb1, pv2, cb2);
196 if (SUCCEEDED(hr))
197 return VINF_SUCCESS;
198
199 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error unlocking output buffer: %Rhrc\n", hr));
200 return VERR_ACCESS_DENIED;
201}
202
203static int dsoundUnlockInput(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
204 LPVOID pv1, LPVOID pv2,
205 DWORD cb1, DWORD cb2)
206{
207 HRESULT hr = IDirectSoundCaptureBuffer8_Unlock(pDSCB, pv1, cb1, pv2, cb2);
208 if (SUCCEEDED(hr))
209 return VINF_SUCCESS;
210
211 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error unlocking input buffer: %Rhrc\n", hr));
212 return VERR_ACCESS_DENIED;
213}
214
215static int dsoundLockOutput(LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
216 DWORD dwOffset, DWORD dwBytes,
217 LPVOID *ppv1, LPVOID *ppv2,
218 DWORD *pcb1, DWORD *pcb2,
219 DWORD dwFlags)
220{
221 int rc = VINF_SUCCESS;
222
223 LPVOID pv1 = NULL;
224 LPVOID pv2 = NULL;
225 DWORD cb1 = 0;
226 DWORD cb2 = 0;
227
228 HRESULT hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
229 if (hr == DSERR_BUFFERLOST)
230 {
231 rc = dsoundPlayRestore(pDSB);
232 if (RT_SUCCESS(rc))
233 {
234 hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
235 if (FAILED(hr))
236 rc = VERR_ACCESS_DENIED;
237 }
238 }
239
240 if (RT_FAILURE(rc))
241 {
242 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error locking output buffer: %Rhrc\n", hr));
243 return rc;
244 }
245
246 if ( (pv1 && (cb1 & pProps->uAlign))
247 || (pv2 && (cb2 & pProps->uAlign)))
248 {
249 LogRelMax(s_cMaxRelLogEntries, ("DSound: Locking playback buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
250 cb1, cb2, pProps->uAlign));
251 dsoundUnlockOutput(pDSB, pv1, pv2, cb1, cb2);
252 return VERR_INVALID_STATE;
253 }
254
255 *ppv1 = pv1;
256 *ppv2 = pv2;
257 *pcb1 = cb1;
258 *pcb2 = cb2;
259
260 return VINF_SUCCESS;
261}
262
263static int dsoundLockInput(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB, PPDMPCMPROPS pProps,
264 DWORD dwOffset, DWORD dwBytes,
265 LPVOID *ppv1, LPVOID *ppv2,
266 DWORD *pcb1, DWORD *pcb2,
267 DWORD dwFlags)
268{
269 LPVOID pv1 = NULL;
270 LPVOID pv2 = NULL;
271 DWORD cb1 = 0;
272 DWORD cb2 = 0;
273
274 HRESULT hr = IDirectSoundCaptureBuffer8_Lock(pDSCB, dwOffset, dwBytes,
275 &pv1, &cb1, &pv2, &cb2, dwFlags);
276 if (FAILED(hr))
277 {
278 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error locking capturing buffer: %Rhrc\n", hr));
279 return VERR_ACCESS_DENIED;
280 }
281
282 if ( (pv1 && (cb1 & pProps->uAlign))
283 || (pv2 && (cb2 & pProps->uAlign)))
284 {
285 LogRelMax(s_cMaxRelLogEntries, ("DSound: Locking capture buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
286 cb1, cb2, pProps->uAlign));
287 dsoundUnlockInput(pDSCB, pv1, pv2, cb1, cb2);
288 return VERR_INVALID_PARAMETER;
289 }
290
291 *ppv1 = pv1;
292 *ppv2 = pv2;
293 *pcb1 = cb1;
294 *pcb2 = cb2;
295
296 return VINF_SUCCESS;
297}
298
299
300/*
301 * DirectSound playback
302 */
303
304static void dsoundPlayInterfaceRelease(PDSOUNDSTREAMOUT pDSoundStrmOut)
305{
306 if (pDSoundStrmOut->pDS)
307 {
308 IDirectSound8_Release(pDSoundStrmOut->pDS);
309 pDSoundStrmOut->pDS = NULL;
310 }
311}
312
313static int dsoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
314{
315 if (pDSoundStrmOut->pDS != NULL)
316 {
317 LogFlowFunc(("DirectSound instance already exists\n"));
318 return VINF_SUCCESS;
319 }
320
321 HRESULT hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL,
322 IID_IDirectSound8, (void **)&pDSoundStrmOut->pDS);
323 if (FAILED(hr))
324 {
325 LogRel(("DSound: Error creating DirectSound instance: %Rhrc\n", hr));
326 }
327 else
328 {
329 hr = IDirectSound8_Initialize(pDSoundStrmOut->pDS, pThis->cfg.pGuidPlay);
330 if (SUCCEEDED(hr))
331 {
332 HWND hWnd = GetDesktopWindow();
333 hr = IDirectSound8_SetCooperativeLevel(pDSoundStrmOut->pDS, hWnd, DSSCL_PRIORITY);
334 if (FAILED(hr))
335 LogRel(("DSound: Error setting cooperative level for window %p: %Rhrc\n", hWnd, hr));
336 }
337 if (FAILED(hr))
338 {
339 if (hr == DSERR_NODRIVER)
340 LogRel(("DSound: DirectSound playback is currently unavailable\n"));
341 else
342 LogRel(("DSound: Error initializing DirectSound: %Rhrc\n", hr));
343
344 dsoundPlayInterfaceRelease(pDSoundStrmOut);
345 }
346 }
347
348 return SUCCEEDED(hr) ? VINF_SUCCESS: VERR_NOT_SUPPORTED;
349}
350
351static void dsoundPlayClose(PDSOUNDSTREAMOUT pDSoundStrmOut)
352{
353 LogFlowFunc(("Closing playback stream %p (buffer %p)\n", pDSoundStrmOut, pDSoundStrmOut->pDSB));
354
355 if (pDSoundStrmOut->pDSB)
356 {
357 HRESULT hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
358 if (FAILED(hr))
359 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error closing playback stream %p: %Rhrc\n", pDSoundStrmOut, hr));
360
361 IDirectSoundBuffer8_Release(pDSoundStrmOut->pDSB);
362 pDSoundStrmOut->pDSB = NULL;
363 }
364
365 dsoundPlayInterfaceRelease(pDSoundStrmOut);
366}
367
368static int dsoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
369{
370 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
371 AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
372
373 LogFlowFunc(("pDSoundStrmOut=%p, cbBufferOut=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
374 pDSoundStrmOut,
375 pThis->cfg.cbBufferOut,
376 pDSoundStrmOut->strmOut.Props.uHz,
377 pDSoundStrmOut->strmOut.Props.cChannels,
378 pDSoundStrmOut->strmOut.Props.cBits,
379 pDSoundStrmOut->strmOut.Props.fSigned));
380
381 if (pDSoundStrmOut->pDSB != NULL)
382 {
383 /* Should not happen but be forgiving. */
384 LogFlowFunc(("DirectSoundBuffer already exists\n"));
385 dsoundPlayClose(pDSoundStrmOut);
386 }
387
388 WAVEFORMATEX wfx;
389 int rc = dsoundWaveFmtFromCfg(&pDSoundStrmOut->streamCfg, &wfx);
390 if (RT_FAILURE(rc))
391 return rc;
392
393 rc = dsoundPlayInterfaceCreate(pThis, pDSoundStrmOut);
394 if (RT_FAILURE(rc))
395 return rc;
396
397 HRESULT hr = S_OK;
398
399 do /* To use breaks. */
400 {
401 DSBUFFERDESC bd;
402 LPDIRECTSOUNDBUFFER pDSB;
403 RT_ZERO(bd);
404 bd.dwSize = sizeof(bd);
405 bd.lpwfxFormat = &wfx;
406 bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
407 bd.dwBufferBytes = pThis->cfg.cbBufferOut;
408 hr = IDirectSound8_CreateSoundBuffer(pDSoundStrmOut->pDS,
409 &bd, &pDSB, NULL);
410 if (FAILED(hr))
411 {
412 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error creating playback stream: %Rhrc\n", hr));
413 break;
414 }
415
416 hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (void **)&pDSoundStrmOut->pDSB);
417 pDSB->Release();
418 if (FAILED(hr))
419 {
420 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error querying interface for playback stream: %Rhrc\n", hr));
421 break;
422 }
423
424 /* Query the actual parameters. */
425 hr = IDirectSoundBuffer8_GetFormat(pDSoundStrmOut->pDSB, &wfx, sizeof(wfx), NULL);
426 if (FAILED(hr))
427 {
428 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error querying format for playback stream: %Rhrc\n", hr));
429 break;
430 }
431
432 DSBCAPS bc;
433 RT_ZERO(bc);
434 bc.dwSize = sizeof(bc);
435 hr = IDirectSoundBuffer8_GetCaps(pDSoundStrmOut->pDSB, &bc);
436 if (FAILED(hr))
437 {
438 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error querying capabilities for playback stream: %Rhrc\n", hr));
439 break;
440 }
441
442 LogFunc(("Playback format:\n"
443 "\tdwBufferBytes = %RI32\n"
444 "\twFormatTag = %RI16\n"
445 "\tnChannels = %RI16\n"
446 "\tnSamplesPerSec = %RU32\n"
447 "\tnAvgBytesPerSec = %RU32\n"
448 "\tnBlockAlign = %RI16\n"
449 "\twBitsPerSample = %RI16\n"
450 "\tcbSize = %RI16\n",
451 bc.dwBufferBytes,
452 wfx.wFormatTag,
453 wfx.nChannels,
454 wfx.nSamplesPerSec,
455 wfx.nAvgBytesPerSec,
456 wfx.nBlockAlign,
457 wfx.wBitsPerSample,
458 wfx.cbSize));
459
460 if (bc.dwBufferBytes & pDSoundStrmOut->strmOut.Props.uAlign)
461 LogRelMax(s_cMaxRelLogEntries, ("DSound: Playback capabilities returned misaligned buffer (size %ld, alignment %RU32)\n",
462 bc.dwBufferBytes, pDSoundStrmOut->strmOut.Props.uAlign + 1));
463
464 if (bc.dwBufferBytes != pThis->cfg.cbBufferOut)
465 LogRelMax(s_cMaxRelLogEntries, ("DSound: Playback buffer size mismatched (DirectSound %ld, requested %ld bytes)\n",
466 bc.dwBufferBytes, pThis->cfg.cbBufferOut));
467
468 /*
469 * Initial state.
470 * dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
471 * playback buffer position.
472 */
473 pDSoundStrmOut->csPlaybackBufferSize = bc.dwBufferBytes >> pDSoundStrmOut->strmOut.Props.cShift;
474 LogFlowFunc(("csPlaybackBufferSize=%ld\n", pDSoundStrmOut->csPlaybackBufferSize));
475
476 } while (0);
477
478 if (SUCCEEDED(hr))
479 return VINF_SUCCESS;
480
481 dsoundPlayClose(pDSoundStrmOut);
482 return VERR_NOT_SUPPORTED;
483}
484
485static void dsoundPlayClearSamples(PDSOUNDSTREAMOUT pDSoundStrmOut)
486{
487 AssertPtrReturnVoid(pDSoundStrmOut);
488
489 LPVOID pv1, pv2;
490 DWORD cb1, cb2;
491 int rc = dsoundLockOutput(pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
492 0, pDSoundStrmOut->csPlaybackBufferSize << pDSoundStrmOut->strmOut.Props.cShift,
493 &pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
494 if (RT_SUCCESS(rc))
495 {
496 int len1 = cb1 >> pDSoundStrmOut->strmOut.Props.cShift;
497 int len2 = cb2 >> pDSoundStrmOut->strmOut.Props.cShift;
498
499 if (pv1 && len1)
500 drvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv1, len1);
501
502 if (pv2 && len2)
503 drvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv2, len2);
504
505 dsoundUnlockOutput(pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
506 }
507}
508
509static int dsoundPlayGetStatus(LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pStatus)
510{
511 AssertPtrReturn(pDSB, VERR_INVALID_POINTER);
512 /* pStatus is optional. */
513
514 int rc = VINF_SUCCESS;
515
516 DWORD dwStatus = 0;
517 HRESULT hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
518 if (SUCCEEDED(hr))
519 {
520 if ((dwStatus & DSBSTATUS_BUFFERLOST) != 0)
521 {
522 rc = dsoundPlayRestore(pDSB);
523 if (RT_SUCCESS(rc))
524 hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
525 }
526 }
527
528 if (FAILED(hr))
529 {
530 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error getting playback status: %Rhrc\n", hr));
531 if (RT_SUCCESS(rc))
532 rc = VERR_NOT_SUPPORTED;
533 }
534
535 if (RT_SUCCESS(rc))
536 {
537 if (pStatus)
538 *pStatus = dwStatus;
539 }
540
541 return rc;
542}
543
544static void dsoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
545{
546 AssertPtrReturnVoid(pThis);
547 AssertPtrReturnVoid(pDSoundStrmOut);
548
549 if (pDSoundStrmOut->pDSB != NULL)
550 {
551 /* This performs some restore, so call it anyway and ignore result. */
552 dsoundPlayGetStatus(pDSoundStrmOut->pDSB, NULL /* Status */);
553
554 LogFlowFunc(("Playback stopped\n"));
555
556 HRESULT hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
557 if (SUCCEEDED(hr))
558 {
559 dsoundPlayClearSamples(pDSoundStrmOut);
560 }
561 else
562 LogRelMax(s_cMaxRelLogEntries, ("DSound: Errpor stopping playback buffer: %Rhrc\n", hr));
563 }
564}
565
566static int dsoundPlayStart(PDSOUNDSTREAMOUT pDSoundStrmOut)
567{
568 AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
569
570 int rc;
571
572 if (pDSoundStrmOut->pDSB != NULL)
573 {
574 DWORD dwStatus;
575 rc = dsoundPlayGetStatus(pDSoundStrmOut->pDSB, &dwStatus);
576 if (RT_SUCCESS(rc))
577 {
578 if (dwStatus & DSBSTATUS_PLAYING)
579 {
580 LogFlowFunc(("Already playing\n"));
581 }
582 else
583 {
584 dsoundPlayClearSamples(pDSoundStrmOut);
585
586 pDSoundStrmOut->fReinitPlayPos = true;
587
588 LogFlowFunc(("Playback started\n"));
589
590 HRESULT hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, DSBPLAY_LOOPING);
591 if (FAILED(hr))
592 {
593 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error starting playback: %Rhrc\n", hr));
594 rc = VERR_NOT_SUPPORTED;
595 }
596 }
597 }
598 }
599 else
600 rc = VERR_INVALID_STATE;
601
602 return rc;
603}
604
605/*
606 * DirectSoundCapture
607 */
608
609static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
610{
611 AssertPtrReturn(pThis, NULL);
612 AssertPtrReturn(pDSoundStrmIn, NULL);
613
614 LPCGUID pGUID = pThis->cfg.pGuidCapture;
615
616 if (!pGUID)
617 {
618 PDSOUNDDEV pDev = NULL;
619
620 switch (pDSoundStrmIn->enmRecSource)
621 {
622 case PDMAUDIORECSOURCE_MIC:
623 {
624 RTListForEach(&pThis->lstDevInput, pDev, DSOUNDDEV, Node)
625 {
626 if (RTStrIStr(pDev->pszName, "Mic")) /** @todo what is with non en_us windows versions? */
627 break;
628 }
629 if (RTListNodeIsDummy(&pThis->lstDevInput, pDev, DSOUNDDEV, Node))
630 pDev = NULL; /* Found nothing. */
631
632 break;
633 }
634
635 case PDMAUDIORECSOURCE_LINE_IN:
636 default:
637 /* Try opening the default device (NULL). */
638 break;
639 }
640
641 if (pDev)
642 {
643 LogRel2(("DSound: Guest \"%s\" is using host \"%s\"\n",
644 drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pDev->pszName));
645
646 pGUID = &pDev->Guid;
647 }
648 }
649
650 char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
651 if (pszGUID)
652 {
653 LogRel(("DSound: Guest \"%s\" is using host device with GUID: %s\n",
654 drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pszGUID));
655 RTStrFree(pszGUID);
656 }
657
658 return pGUID;
659}
660
661static void dsoundCaptureInterfaceRelease(PDSOUNDSTREAMIN pDSoundStrmIn)
662{
663 if (pDSoundStrmIn->pDSC)
664 {
665 IDirectSoundCapture_Release(pDSoundStrmIn->pDSC);
666 pDSoundStrmIn->pDSC = NULL;
667 }
668}
669
670static int dsoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
671{
672 if (pDSoundStrmIn->pDSC != NULL)
673 {
674 LogFunc(("DSound: DirectSoundCapture instance already exists\n"));
675 return VINF_SUCCESS;
676 }
677
678 HRESULT hr = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL,
679 IID_IDirectSoundCapture8, (void **)&pDSoundStrmIn->pDSC);
680 if (FAILED(hr))
681 {
682 LogRel(("DSound: Error creating capture instance: %Rhrc\n", hr));
683 }
684 else
685 {
686 LPCGUID pGUID = dsoundCaptureSelectDevice(pThis, pDSoundStrmIn);
687 hr = IDirectSoundCapture_Initialize(pDSoundStrmIn->pDSC, pGUID);
688 if (FAILED(hr))
689 {
690 if (hr == DSERR_NODRIVER)
691 LogRel(("DSound: DirectSound capture is currently unavailable\n"));
692 else
693 LogRel(("DSound: Error initializing capture: %Rhrc\n", hr));
694 dsoundCaptureInterfaceRelease(pDSoundStrmIn);
695 }
696 }
697
698 return SUCCEEDED(hr) ? VINF_SUCCESS: VERR_NOT_SUPPORTED;
699}
700
701static void dsoundCaptureClose(PDSOUNDSTREAMIN pDSoundStrmIn)
702{
703 AssertPtrReturnVoid(pDSoundStrmIn);
704
705 LogFlowFunc(("pDSoundStrmIn=%p, pDSCB=%p\n", pDSoundStrmIn, pDSoundStrmIn->pDSCB));
706
707 if (pDSoundStrmIn->pDSCB)
708 {
709 HRESULT hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
710 if (FAILED (hr))
711 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error stopping capture buffer: %Rhrc\n", hr));
712
713 IDirectSoundCaptureBuffer8_Release(pDSoundStrmIn->pDSCB);
714 pDSoundStrmIn->pDSCB = NULL;
715 }
716
717 dsoundCaptureInterfaceRelease(pDSoundStrmIn);
718}
719
720static int dsoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
721{
722 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
723 AssertPtrReturn(pDSoundStrmIn, VERR_INVALID_POINTER);
724
725 LogFlowFunc(("pDSoundStrmIn=%p, cbBufferIn=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
726 pDSoundStrmIn,
727 pThis->cfg.cbBufferIn,
728 pDSoundStrmIn->strmIn.Props.uHz,
729 pDSoundStrmIn->strmIn.Props.cChannels,
730 pDSoundStrmIn->strmIn.Props.cBits,
731 pDSoundStrmIn->strmIn.Props.fSigned));
732
733 if (pDSoundStrmIn->pDSCB != NULL)
734 {
735 /* Should not happen but be forgiving. */
736 LogFlowFunc(("Capture buffer already exists\n"));
737 dsoundCaptureClose(pDSoundStrmIn);
738 }
739
740 WAVEFORMATEX wfx;
741 int rc = dsoundWaveFmtFromCfg(&pDSoundStrmIn->streamCfg, &wfx);
742 if (RT_FAILURE(rc))
743 return rc;
744
745 rc = dsoundCaptureInterfaceCreate(pThis, pDSoundStrmIn);
746 if (RT_FAILURE(rc))
747 return rc;
748
749 HRESULT hr = S_OK;
750
751 do /* To use breaks. */
752 {
753 DSCBUFFERDESC bd;
754 LPDIRECTSOUNDCAPTUREBUFFER pDSCB = NULL;
755 RT_ZERO(bd);
756 bd.dwSize = sizeof(bd);
757 bd.lpwfxFormat = &wfx;
758 bd.dwBufferBytes = pThis->cfg.cbBufferIn;
759 hr = IDirectSoundCapture_CreateCaptureBuffer(pDSoundStrmIn->pDSC,
760 &bd, &pDSCB, NULL);
761 if (FAILED(hr))
762 {
763 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error creating capture buffer: %Rhrc\n", hr));
764 pDSoundStrmIn->pDSCB = NULL;
765 break;
766 }
767
768 hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pDSoundStrmIn->pDSCB);
769 IDirectSoundCaptureBuffer_Release(pDSCB);
770 if (FAILED(hr))
771 {
772 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error querying for capture buffer interface: %Rhrc\n", hr));
773 break;
774 }
775
776 /* Query the actual parameters. */
777 DWORD cbReadPos = 0;
778 hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pDSoundStrmIn->pDSCB, NULL, &cbReadPos);
779 if (FAILED(hr))
780 {
781 cbReadPos = 0;
782 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error retrieving current position for capture stream: %Rhrc\n", hr));
783 }
784
785 RT_ZERO(wfx);
786 hr = IDirectSoundCaptureBuffer8_GetFormat(pDSoundStrmIn->pDSCB, &wfx, sizeof(wfx), NULL);
787 if (FAILED(hr))
788 {
789 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error querying format for capture stream: %Rhrc\n", hr));
790 break;
791 }
792
793 DSCBCAPS bc;
794 RT_ZERO(bc);
795 bc.dwSize = sizeof(bc);
796 hr = IDirectSoundCaptureBuffer8_GetCaps(pDSoundStrmIn->pDSCB, &bc);
797 if (FAILED (hr))
798 {
799 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error querying capabilities for capture stream: %Rhrc\n", hr));
800 break;
801 }
802
803 LogFunc(("Capture format:\n"
804 "\tdwBufferBytes = %RI32\n"
805 "\twFormatTag = %RI16\n"
806 "\tnChannels = %RI16\n"
807 "\tnSamplesPerSec = %RU32\n"
808 "\tnAvgBytesPerSec = %RU32\n"
809 "\tnBlockAlign = %RI16\n"
810 "\twBitsPerSample = %RI16\n"
811 "\tcbSize = %RI16\n",
812 bc.dwBufferBytes,
813 wfx.wFormatTag,
814 wfx.nChannels,
815 wfx.nSamplesPerSec,
816 wfx.nAvgBytesPerSec,
817 wfx.nBlockAlign,
818 wfx.wBitsPerSample,
819 wfx.cbSize));
820
821 if (bc.dwBufferBytes & pDSoundStrmIn->strmIn.Props.uAlign)
822 LogRelMax(s_cMaxRelLogEntries, ("DSound: Capture capabilities returned misaligned buffer (size %ld, alignment %RU32)\n",
823 bc.dwBufferBytes, pDSoundStrmIn->strmIn.Props.uAlign + 1));
824
825 if (bc.dwBufferBytes != pThis->cfg.cbBufferIn)
826 LogRelMax(s_cMaxRelLogEntries, ("DSound: Capture buffer size mismatched (DirectSound %ld, requested %ld bytes)\n",
827 bc.dwBufferBytes, pThis->cfg.cbBufferIn));
828
829 /* Initial state: reading at the initial capture position. */
830 pDSoundStrmIn->csCaptureReadPos = cbReadPos >> pDSoundStrmIn->strmIn.Props.cShift;
831 pDSoundStrmIn->csCaptureBufferSize = bc.dwBufferBytes >> pDSoundStrmIn->strmIn.Props.cShift;
832
833 LogFlowFunc(("csCaptureReadPos=%ld, csCaptureBufferSize=%ld\n",
834 pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize));
835
836 /* Update status. */
837 pDSoundStrmIn->hrLastCaptureIn = S_OK;
838
839 } while (0);
840
841 if (SUCCEEDED(hr))
842 return VINF_SUCCESS;
843
844 dsoundCaptureClose(pDSoundStrmIn);
845 return VERR_NOT_SUPPORTED;
846}
847
848static void dsoundCaptureStop(PDSOUNDSTREAMIN pDSoundStrmIn)
849{
850 AssertPtrReturnVoid(pDSoundStrmIn);
851
852 if (pDSoundStrmIn->pDSCB)
853 {
854 LogFlowFunc(("Capturing stopped\n"));
855
856 HRESULT hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
857 if (FAILED(hr))
858 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error stopping capture buffer: %Rhrc\n", hr));
859 }
860}
861
862static int dsoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
863{
864 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
865 AssertPtrReturn(pDSoundStrmIn, VERR_INVALID_POINTER);
866
867 HRESULT hr;
868
869 if (pDSoundStrmIn->pDSCB != NULL)
870 {
871 DWORD dwStatus;
872 hr = IDirectSoundCaptureBuffer8_GetStatus(pDSoundStrmIn->pDSCB, &dwStatus);
873 if (FAILED(hr))
874 {
875 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error getting capture buffer status: %Rhrc\n", hr));
876 }
877 else
878 {
879 if (dwStatus & DSCBSTATUS_CAPTURING)
880 {
881 LogFlowFunc(("Already capturing\n"));
882 }
883 else
884 {
885 LogFlowFunc(("Capturig started\n"));
886 hr = IDirectSoundCaptureBuffer8_Start(pDSoundStrmIn->pDSCB, DSCBSTART_LOOPING);
887 if (FAILED (hr))
888 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error starting capture: %Rhrc\n", hr));
889 }
890 }
891 }
892 else
893 {
894 AssertMsgFailed(("No/invalid capture buffer\n"));
895 hr = E_FAIL;
896 }
897
898 return SUCCEEDED(hr) ? VINF_SUCCESS: VERR_NOT_SUPPORTED;
899}
900
901static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID lpGUID,
902 LPCWSTR lpwstrDescription, PDSOUNDDEV *ppDev)
903{
904 AssertPtrReturn(pList, VERR_INVALID_POINTER);
905 AssertPtrReturn(lpGUID, VERR_INVALID_POINTER);
906 AssertPtrReturn(lpwstrDescription, VERR_INVALID_POINTER);
907
908 PDSOUNDDEV pDev = (PDSOUNDDEV)RTMemAlloc(sizeof(DSOUNDDEV));
909 if (!pDev)
910 return VERR_NO_MEMORY;
911
912 int rc = RTUtf16ToUtf8(lpwstrDescription, &pDev->pszName);
913 if (RT_SUCCESS(rc))
914 memcpy(&pDev->Guid, lpGUID, sizeof(GUID));
915
916 if (RT_SUCCESS(rc))
917 RTListAppend(pList, &pDev->Node);
918
919 if (ppDev)
920 *ppDev = pDev;
921
922 return rc;
923}
924
925static void dsoundDevRemove(PDSOUNDDEV pDev)
926{
927 if (pDev)
928 {
929 RTStrFree(pDev->pszName);
930 pDev->pszName = NULL;
931
932 RTListNodeRemove(&pDev->Node);
933
934 RTMemFree(pDev);
935 }
936}
937
938static void dsoundLogDevice(const char *pszType, LPGUID lpGUID, LPCWSTR lpwstrDescription, LPCWSTR lpwstrModule)
939{
940 AssertPtrReturnVoid(pszType);
941 AssertPtrReturnVoid(lpGUID);
942 AssertPtrReturnVoid(lpwstrDescription);
943 AssertPtrReturnVoid(lpwstrModule);
944
945 char *pszGUID = dsoundGUIDToUtf8StrA(lpGUID);
946 if (pszGUID)
947 {
948 LogRel(("DSound: %s: GUID: %s [%ls] (Module: %ls)\n",
949 pszType, pszGUID, lpwstrDescription, lpwstrModule));
950
951 RTStrFree(pszGUID);
952 }
953}
954
955static BOOL CALLBACK dsoundEnumCallback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
956 LPCWSTR lpwstrModule, LPVOID lpContext)
957{
958 AssertPtrReturn(lpContext, FALSE);
959
960 PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
961 AssertPtrReturn(pCtx, FALSE);
962 AssertPtrReturn(pCtx->pDrv, FALSE);
963 AssertPtrReturn(pCtx->pCfg, FALSE);
964
965 if (!lpGUID)
966 return TRUE;
967
968 AssertPtrReturn(lpwstrDescription, FALSE);
969 AssertPtrReturn(lpwstrModule, FALSE);
970
971 dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
972
973 int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
974 lpGUID, lpwstrDescription, NULL /* ppDev */);
975 if (RT_FAILURE(rc))
976 return FALSE; /* Abort enumeration. */
977
978 pCtx->pCfg->cMaxHstStrmsOut++;
979
980 return TRUE;
981}
982
983static BOOL CALLBACK dsoundCaptureEnumCallback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
984 LPCWSTR lpwstrModule, LPVOID lpContext)
985{
986 PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
987 AssertPtrReturn(pCtx, FALSE);
988 AssertPtrReturn(pCtx->pDrv, FALSE);
989 AssertPtrReturn(pCtx->pCfg, FALSE);
990
991 if (!lpGUID)
992 return TRUE;
993
994 dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
995
996 int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
997 lpGUID, lpwstrDescription, NULL /* ppDev */);
998 if (RT_FAILURE(rc))
999 return FALSE; /* Abort enumeration. */
1000
1001 pCtx->pCfg->cMaxHstStrmsIn++;
1002
1003 return TRUE;
1004}
1005
1006
1007/*
1008 * PDMIHOSTAUDIO
1009 */
1010
1011static DECLCALLBACK(int) drvHostDSoundInitOut(PPDMIHOSTAUDIO pInterface,
1012 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
1013 uint32_t *pcSamples)
1014{
1015 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
1016 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1017 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1018 /* pcSamples is optional. */
1019
1020 LogFlowFunc(("pHstStrmOut=%p, pCfg=%p\n", pHstStrmOut, pCfg));
1021
1022 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1023 PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
1024
1025 pDSoundStrmOut->streamCfg = *pCfg;
1026 pDSoundStrmOut->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1027
1028 int rc = drvAudioStreamCfgToProps(&pDSoundStrmOut->streamCfg, &pDSoundStrmOut->strmOut.Props);
1029 if (RT_SUCCESS(rc))
1030 {
1031 pDSoundStrmOut->pDS = NULL;
1032 pDSoundStrmOut->pDSB = NULL;
1033 pDSoundStrmOut->cbPlayWritePos = 0;
1034 pDSoundStrmOut->fReinitPlayPos = true;
1035 pDSoundStrmOut->csPlaybackBufferSize = 0;
1036
1037 if (pcSamples)
1038 *pcSamples = pThis->cfg.cbBufferOut >> pHstStrmOut->Props.cShift;
1039
1040 /* Try to open playback in case the device is already there. */
1041 dsoundPlayOpen(pThis, pDSoundStrmOut);
1042 }
1043 else
1044 {
1045 RT_ZERO(pDSoundStrmOut->streamCfg);
1046 }
1047
1048 LogFlowFuncLeaveRC(rc);
1049 return rc;
1050}
1051
1052static DECLCALLBACK(int) drvHostDSoundControlOut(PPDMIHOSTAUDIO pInterface,
1053 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
1054{
1055 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
1056 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1057
1058 LogFlowFunc(("pHstStrmOut=%p, cmd=%d\n", pHstStrmOut, enmStreamCmd));
1059
1060 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1061 PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
1062
1063 int rc = VINF_SUCCESS;
1064 switch (enmStreamCmd)
1065 {
1066 case PDMAUDIOSTREAMCMD_ENABLE:
1067 {
1068 /* Try to start playback. If it fails, then reopen and try again. */
1069 rc = dsoundPlayStart(pDSoundStrmOut);
1070 if (RT_FAILURE(rc))
1071 {
1072 dsoundPlayClose(pDSoundStrmOut);
1073 dsoundPlayOpen(pThis, pDSoundStrmOut);
1074
1075 rc = dsoundPlayStart(pDSoundStrmOut);
1076 }
1077
1078 break;
1079 }
1080
1081 case PDMAUDIOSTREAMCMD_DISABLE:
1082 {
1083 dsoundPlayStop(pThis, pDSoundStrmOut);
1084 break;
1085 }
1086
1087 default:
1088 {
1089 AssertMsgFailed(("Invalid command: %ld\n", enmStreamCmd));
1090 rc = VERR_INVALID_PARAMETER;
1091 break;
1092 }
1093 }
1094
1095 LogFlowFuncLeaveRC(rc);
1096 return rc;
1097}
1098
1099
1100static DECLCALLBACK(int) drvHostDSoundPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
1101 uint32_t *pcSamplesPlayed)
1102{
1103 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
1104 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1105 /* pcSamplesPlayed is optional. */
1106
1107 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1108 PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
1109
1110 int rc = VINF_SUCCESS;
1111 uint32_t cReadTotal = 0;
1112
1113 do
1114 {
1115 LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
1116 if (!pDSB)
1117 break;
1118
1119 int cShift = pHstStrmOut->Props.cShift;
1120 DWORD cbBuffer = pDSoundStrmOut->csPlaybackBufferSize << cShift;
1121
1122 DWORD cbPlayPos, cbWritePos;
1123 HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, &cbWritePos);
1124 if (hr == DSERR_BUFFERLOST)
1125 {
1126 rc = dsoundPlayRestore(pDSB);
1127 if (RT_FAILURE(rc))
1128 break;
1129
1130 hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, &cbWritePos);
1131 if (hr == DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
1132 break;
1133 }
1134
1135 if (FAILED(hr))
1136 {
1137 LogRelMax(s_cMaxRelLogEntries, ("Error retrieving current playback position: %Rhrc\n", hr));
1138 break;
1139 }
1140
1141 DWORD cbFree;
1142 DWORD cbPlayWritePos;
1143 if (pDSoundStrmOut->fReinitPlayPos)
1144 {
1145 pDSoundStrmOut->fReinitPlayPos = false;
1146
1147 pDSoundStrmOut->cbPlayWritePos = cbWritePos;
1148
1149 cbPlayWritePos = pDSoundStrmOut->cbPlayWritePos;
1150 cbFree = cbBuffer - dsoundRingDistance(cbWritePos, cbPlayPos, cbBuffer);
1151 }
1152 else
1153 {
1154 /* Full buffer? */
1155 if (pDSoundStrmOut->cbPlayWritePos == cbPlayPos)
1156 break;
1157
1158 cbPlayWritePos = pDSoundStrmOut->cbPlayWritePos;
1159 cbFree = dsoundRingDistance(cbPlayPos, cbPlayWritePos, cbBuffer);
1160 }
1161
1162 uint32_t csLive = drvAudioHstOutSamplesLive(pHstStrmOut);
1163 uint32_t cbLive = csLive << cShift;
1164
1165 /* Do not write more than available space in the DirectSound playback buffer. */
1166 cbLive = RT_MIN(cbFree, cbLive);
1167
1168 cbLive &= ~pHstStrmOut->Props.uAlign;
1169 if (cbLive == 0 || cbLive > cbBuffer)
1170 {
1171 LogFlowFunc(("cbLive=%RU32, cbBuffer=%ld, cbPlayWritePos=%ld, cbPlayPos=%ld\n",
1172 cbLive, cbBuffer, cbPlayWritePos, cbPlayPos));
1173 break;
1174 }
1175
1176 LPVOID pv1, pv2;
1177 DWORD cb1, cb2;
1178 rc = dsoundLockOutput(pDSB, &pHstStrmOut->Props, cbPlayWritePos, cbLive,
1179 &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
1180 if (RT_FAILURE(rc))
1181 break;
1182
1183 DWORD len1 = cb1 >> cShift;
1184 DWORD len2 = cb2 >> cShift;
1185
1186 uint32_t cRead = 0;
1187
1188 if (pv1 && cb1)
1189 {
1190 rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv1, cb1, &cRead);
1191 if (RT_SUCCESS(rc))
1192 cReadTotal += cRead;
1193 }
1194
1195 if ( RT_SUCCESS(rc)
1196 && cReadTotal == len1
1197 && pv2 && cb2)
1198 {
1199 rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv2, cb2, &cRead);
1200 if (RT_SUCCESS(rc))
1201 cReadTotal += cRead;
1202 }
1203
1204 dsoundUnlockOutput(pDSB, pv1, pv2, cb1, cb2);
1205
1206 pDSoundStrmOut->cbPlayWritePos = (cbPlayWritePos + (cReadTotal << cShift)) % cbBuffer;
1207
1208 LogFlowFunc(("%RU32 (%RU32 samples) out of %RU32%s, buffer write pos %ld -> %ld, rc=%Rrc\n",
1209 AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal), cReadTotal, cbLive,
1210 cbLive != AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal) ? " !!!": "",
1211 cbPlayWritePos, pDSoundStrmOut->cbPlayWritePos, rc));
1212
1213 if (cReadTotal)
1214 {
1215 AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
1216 rc = VINF_SUCCESS; /* Played something. */
1217 }
1218
1219 } while (0);
1220
1221 if (pcSamplesPlayed)
1222 *pcSamplesPlayed = cReadTotal;
1223
1224 return rc;
1225}
1226
1227static DECLCALLBACK(int) drvHostDSoundFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
1228{
1229 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1230 PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
1231
1232 dsoundPlayClose(pDSoundStrmOut);
1233
1234 pDSoundStrmOut->cbPlayWritePos = 0;
1235 pDSoundStrmOut->fReinitPlayPos = true;
1236 pDSoundStrmOut->csPlaybackBufferSize = 0;
1237 RT_ZERO(pDSoundStrmOut->streamCfg);
1238
1239 return VINF_SUCCESS;
1240}
1241
1242static DECLCALLBACK(int) drvHostDSoundInitIn(PPDMIHOSTAUDIO pInterface,
1243 PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
1244 PDMAUDIORECSOURCE enmRecSource,
1245 uint32_t *pcSamples)
1246{
1247 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1248 PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
1249
1250 LogFlowFunc(("pHstStrmIn=%p, pAudioSettings=%p, enmRecSource=%ld\n",
1251 pHstStrmIn, pCfg, enmRecSource));
1252
1253 pDSoundStrmIn->streamCfg = *pCfg;
1254 pDSoundStrmIn->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1255
1256 /** @todo caller should already init Props? */
1257 int rc = drvAudioStreamCfgToProps(&pDSoundStrmIn->streamCfg, &pHstStrmIn->Props);
1258 if (RT_SUCCESS(rc))
1259 {
1260 /* Init the stream structure and save relevant information to it. */
1261 pDSoundStrmIn->csCaptureReadPos = 0;
1262 pDSoundStrmIn->csCaptureBufferSize = 0;
1263 pDSoundStrmIn->pDSC = NULL;
1264 pDSoundStrmIn->pDSCB = NULL;
1265 pDSoundStrmIn->enmRecSource = enmRecSource;
1266 pDSoundStrmIn->hrLastCaptureIn = S_OK;
1267
1268 if (pcSamples)
1269 *pcSamples = pThis->cfg.cbBufferIn >> pHstStrmIn->Props.cShift;
1270
1271 /* Try to open capture in case the device is already there. */
1272 dsoundCaptureOpen(pThis, pDSoundStrmIn);
1273 }
1274 else
1275 {
1276 RT_ZERO(pDSoundStrmIn->streamCfg);
1277 }
1278
1279 LogFlowFuncLeaveRC(rc);
1280 return rc;
1281}
1282
1283static DECLCALLBACK(int) drvHostDSoundControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
1284 PDMAUDIOSTREAMCMD enmStreamCmd)
1285{
1286 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
1287 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1288
1289 LogFlowFunc(("pHstStrmIn=%p, enmStreamCmd=%ld\n", pHstStrmIn, enmStreamCmd));
1290
1291 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1292 PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
1293
1294 int rc = VINF_SUCCESS;
1295
1296 switch (enmStreamCmd)
1297 {
1298 case PDMAUDIOSTREAMCMD_ENABLE:
1299 {
1300 /* Try to start capture. If it fails, then reopen and try again. */
1301 rc = dsoundCaptureStart(pThis, pDSoundStrmIn);
1302 if (RT_FAILURE(rc))
1303 {
1304 dsoundCaptureClose(pDSoundStrmIn);
1305 dsoundCaptureOpen(pThis, pDSoundStrmIn);
1306
1307 rc = dsoundCaptureStart(pThis, pDSoundStrmIn);
1308 }
1309 } break;
1310
1311 case PDMAUDIOSTREAMCMD_DISABLE:
1312 {
1313 dsoundCaptureStop(pDSoundStrmIn);
1314 } break;
1315
1316 default:
1317 {
1318 AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
1319 rc = VERR_INVALID_PARAMETER;
1320 } break;
1321 }
1322
1323 return rc;
1324}
1325
1326static DECLCALLBACK(int) drvHostDSoundCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
1327 uint32_t *pcSamplesCaptured)
1328{
1329 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1330 PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
1331 LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pDSoundStrmIn->pDSCB;
1332
1333 int rc;
1334
1335 if (pDSCB == NULL)
1336 {
1337 if (pcSamplesCaptured) /** @todo single point of return */
1338 *pcSamplesCaptured = 0;
1339 return VINF_SUCCESS;
1340 }
1341
1342 /* Get DirectSound capture position in bytes. */
1343 DWORD cbReadPos;
1344 HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &cbReadPos);
1345 if (FAILED(hr))
1346 {
1347 if (hr != pDSoundStrmIn->hrLastCaptureIn)
1348 {
1349 LogRelMax(s_cMaxRelLogEntries, ("DSound: Error retrieving current capture position: %Rhrc\n", hr));
1350 pDSoundStrmIn->hrLastCaptureIn = hr;
1351 }
1352
1353 if (pcSamplesCaptured)
1354 *pcSamplesCaptured = 0;
1355 return VINF_SUCCESS;
1356 }
1357 pDSoundStrmIn->hrLastCaptureIn = hr;
1358
1359 if (cbReadPos & pHstStrmIn->Props.uAlign)
1360 LogFunc(("Misaligned read position %ld (alignment: %RU32)\n", cbReadPos, pHstStrmIn->Props.uAlign));
1361
1362 /* Capture position in samples. */
1363 DWORD csReadPos = cbReadPos >> pHstStrmIn->Props.cShift;
1364
1365 /* Number of samples available in the DirectSound capture buffer. */
1366 DWORD csCaptured = dsoundRingDistance(csReadPos, pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize);
1367 if (csCaptured == 0)
1368 {
1369 if (pcSamplesCaptured)
1370 *pcSamplesCaptured = 0;
1371 return VINF_SUCCESS;
1372 }
1373
1374 /* Using as an intermediate not circular buffer. */
1375 AudioMixBufReset(&pHstStrmIn->MixBuf);
1376
1377 /* Get number of free samples in the mix buffer and check that is has free space */
1378 uint32_t csMixFree = AudioMixBufFree(&pHstStrmIn->MixBuf);
1379 if (csMixFree == 0)
1380 {
1381 LogRelMax(s_cMaxRelLogEntries, ("DSound: Capture buffer full\n"));
1382 if (pcSamplesCaptured)
1383 *pcSamplesCaptured = 0;
1384 return VINF_SUCCESS;
1385 }
1386
1387 LogFlowFunc(("csMixFree=%RU32, csReadPos=%ld, csCaptureReadPos=%ld, csCaptured=%ld\n",
1388 csMixFree, csReadPos, pDSoundStrmIn->csCaptureReadPos, csCaptured));
1389
1390 /* No need to fetch more samples than mix buffer can receive. */
1391 csCaptured = RT_MIN(csCaptured, csMixFree);
1392
1393 /* Lock relevant range in the DirectSound capture buffer. */
1394 LPVOID pv1, pv2;
1395 DWORD cb1, cb2;
1396 rc = dsoundLockInput(pDSCB, &pHstStrmIn->Props,
1397 pDSoundStrmIn->csCaptureReadPos << pHstStrmIn->Props.cShift,
1398 csCaptured << pHstStrmIn->Props.cShift,
1399 &pv1, &pv2, &cb1, &cb2,
1400 0 /* dwFlags */);
1401 if (RT_FAILURE(rc))
1402 {
1403 if (pcSamplesCaptured)
1404 *pcSamplesCaptured = 0;
1405 return VINF_SUCCESS;
1406 }
1407
1408 DWORD len1 = cb1 >> pHstStrmIn->Props.cShift;
1409 DWORD len2 = cb2 >> pHstStrmIn->Props.cShift;
1410
1411 uint32_t csWrittenTotal = 0;
1412 uint32_t csWritten;
1413 if (pv1 && len1)
1414 {
1415 rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, 0 /* offWrite */,
1416 pv1, cb1, &csWritten);
1417 if (RT_SUCCESS(rc))
1418 csWrittenTotal += csWritten;
1419 }
1420
1421 if ( RT_SUCCESS(rc)
1422 && csWrittenTotal == len1
1423 && pv2 && len2)
1424 {
1425 rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, csWrittenTotal,
1426 pv2, cb2, &csWritten);
1427 if (RT_SUCCESS(rc))
1428 csWrittenTotal += csWritten;
1429 }
1430
1431 dsoundUnlockInput(pDSCB, pv1, pv2, cb1, cb2);
1432
1433 uint32_t csProcessed = 0;
1434 if (csWrittenTotal != 0)
1435 {
1436 /* Captured something. */
1437 rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, csWrittenTotal,
1438 &csProcessed);
1439 }
1440
1441 if (RT_SUCCESS(rc))
1442 {
1443 pDSoundStrmIn->csCaptureReadPos = (pDSoundStrmIn->csCaptureReadPos + csProcessed) % pDSoundStrmIn->csCaptureBufferSize;
1444 LogFlowFunc(("%ld (%ld+%ld), processed %RU32/%RU32\n",
1445 csCaptured, len1, len2, csProcessed, csWrittenTotal));
1446 }
1447
1448 if (pcSamplesCaptured)
1449 *pcSamplesCaptured = csProcessed;
1450
1451 return rc;
1452}
1453
1454static DECLCALLBACK(int) drvHostDSoundFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
1455{
1456 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1457 PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
1458
1459 dsoundCaptureClose(pDSoundStrmIn);
1460
1461 pDSoundStrmIn->csCaptureReadPos = 0;
1462 pDSoundStrmIn->csCaptureBufferSize = 0;
1463 RT_ZERO(pDSoundStrmIn->streamCfg);
1464
1465 return VINF_SUCCESS;
1466}
1467
1468static DECLCALLBACK(bool) drvHostDSoundIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
1469{
1470 NOREF(pInterface);
1471 NOREF(enmDir);
1472 return true; /* Always all enabled. */
1473}
1474
1475static DECLCALLBACK(int) drvHostDSoundGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
1476{
1477 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1478
1479 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1480
1481 dsoundFreeDeviceLists(pThis);
1482
1483 pCfg->cbStreamOut = sizeof(DSOUNDSTREAMOUT);
1484 pCfg->cbStreamIn = sizeof(DSOUNDSTREAMIN);
1485
1486 pCfg->cMaxHstStrmsOut = 0;
1487 pCfg->cMaxHstStrmsIn = 0;
1488
1489 DSOUNDENUMCBCTX ctx = { pThis, pCfg };
1490
1491 HRESULT hr = DirectSoundEnumerateW(&dsoundEnumCallback, &ctx);
1492 if (FAILED(hr))
1493 LogRel(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
1494
1495 LogRel(("DSound: Found %RU32 host playback devices\n", pCfg->cMaxHstStrmsOut));
1496 if (pCfg->cMaxHstStrmsOut == 0)
1497 pCfg->cMaxHstStrmsOut = 1; /* Support at least one stream. */
1498
1499 hr = DirectSoundCaptureEnumerateW(&dsoundCaptureEnumCallback, &ctx);
1500 if (FAILED(hr))
1501 LogRel(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
1502
1503 LogRel(("DSound: Found %RU32 host capturing devices\n", pCfg->cMaxHstStrmsIn));
1504 if (pCfg->cMaxHstStrmsIn < 2)
1505 {
1506 LogRel(("DSound: Adjusting the number of host capturing devices from %RU32 to 2\n", pCfg->cMaxHstStrmsIn));
1507 pCfg->cMaxHstStrmsIn = 2; /* Support at least two streams (line in + mic). */
1508 }
1509
1510 return VINF_SUCCESS;
1511}
1512
1513static DECLCALLBACK(void) drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
1514{
1515 NOREF(pInterface);
1516}
1517
1518static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
1519{
1520 PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
1521
1522 LogFlowFuncEnter();
1523
1524 /* Verify that IDirectSound is available. */
1525 LPDIRECTSOUND pDirectSound = NULL;
1526 HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_ALL,
1527 IID_IDirectSound, (void **)&pDirectSound);
1528 if (SUCCEEDED(hr))
1529 IDirectSound_Release(pDirectSound);
1530 else
1531 LogRel(("DSound: DirectSound not available: %Rhrc\n", hr));
1532
1533 int rc = SUCCEEDED(hr) ? VINF_SUCCESS: VERR_NOT_SUPPORTED;
1534
1535 LogFlowFuncLeaveRC(rc);
1536 return rc;
1537}
1538
1539static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1540{
1541 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1542 PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
1543
1544 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1545 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
1546 return NULL;
1547}
1548
1549static int dsoundConfigQueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
1550{
1551 /** @todo r=bird: What's wrong with CFGMR3QueryStringAlloc ?? */
1552 size_t cbString;
1553 int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
1554 if (RT_SUCCESS(rc))
1555 {
1556 char *pszString = RTStrAlloc(cbString);
1557 if (pszString)
1558 {
1559 rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
1560 if (RT_SUCCESS(rc))
1561 *ppszString = pszString;
1562 else
1563 RTStrFree(pszString);
1564 }
1565 else
1566 rc = VERR_NO_MEMORY;
1567 }
1568 return rc;
1569}
1570
1571static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID *pUuid)
1572{
1573 LPCGUID pGuid = NULL;
1574
1575 char *pszGuid = NULL;
1576 dsoundConfigQueryStringAlloc(pCfg, pszName, &pszGuid);
1577 if (pszGuid)
1578 {
1579 int rc = RTUuidFromStr(pUuid, pszGuid);
1580 if (RT_SUCCESS(rc))
1581 pGuid = (LPCGUID)&pUuid;
1582 else
1583 LogRel(("DSound: Error parsing device GUID for device '%s': %Rrc\n", pszName, rc));
1584
1585 RTStrFree(pszGuid);
1586 }
1587
1588 return pGuid;
1589}
1590
1591static void dSoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
1592{
1593 unsigned int uBufsizeOut, uBufsizeIn;
1594
1595 CFGMR3QueryUIntDef(pCfg, "BufsizeOut", &uBufsizeOut, _16K);
1596 CFGMR3QueryUIntDef(pCfg, "BufsizeIn", &uBufsizeIn, _16K);
1597 pThis->cfg.cbBufferOut = uBufsizeOut;
1598 pThis->cfg.cbBufferIn = uBufsizeIn;
1599
1600 pThis->cfg.pGuidPlay = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->cfg.uuidPlay);
1601 pThis->cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn", &pThis->cfg.uuidCapture);
1602
1603 LogFlowFunc(("BufsizeOut %u, BufsizeIn %u, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n",
1604 pThis->cfg.cbBufferOut,
1605 pThis->cfg.cbBufferIn,
1606 &pThis->cfg.uuidPlay,
1607 &pThis->cfg.uuidCapture));
1608}
1609
1610static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
1611{
1612 PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
1613 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1614 LogFlowFuncEnter();
1615
1616 if (pThis->pDrvIns)
1617 CoUninitialize();
1618
1619 LogFlowFuncLeave();
1620}
1621
1622/**
1623 * Construct a DirectSound Audio driver instance.
1624 *
1625 * @copydoc FNPDMDRVCONSTRUCT
1626 */
1627static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1628{
1629 PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
1630 LogRel(("Audio: Initializing DirectSound audio driver\n"));
1631 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1632
1633 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
1634 if (FAILED(hr))
1635 {
1636 LogRel(("DSound: Error initializing COM: %Rhrc\n", hr));
1637 return VERR_NOT_SUPPORTED;
1638 }
1639
1640 /*
1641 * Init the static parts.
1642 */
1643 pThis->pDrvIns = pDrvIns;
1644 /* IBase */
1645 pDrvIns->IBase.pfnQueryInterface = drvHostDSoundQueryInterface;
1646 /* IHostAudio */
1647 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostDSound);
1648
1649 RTListInit(&pThis->lstDevInput);
1650 RTListInit(&pThis->lstDevOutput);
1651
1652 /*
1653 * Initialize configuration values.
1654 */
1655 dSoundConfigInit(pThis, pCfg);
1656
1657 return VINF_SUCCESS;
1658}
1659
1660/**
1661 * PDM driver registration.
1662 */
1663const PDMDRVREG g_DrvHostDSound =
1664{
1665 /* u32Version */
1666 PDM_DRVREG_VERSION,
1667 /* szName */
1668 "DSoundAudio",
1669 /* szRCMod */
1670 "",
1671 /* szR0Mod */
1672 "",
1673 /* pszDescription */
1674 "DirectSound Audio host driver",
1675 /* fFlags */
1676 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1677 /* fClass. */
1678 PDM_DRVREG_CLASS_AUDIO,
1679 /* cMaxInstances */
1680 ~0U,
1681 /* cbInstance */
1682 sizeof(DRVHOSTDSOUND),
1683 /* pfnConstruct */
1684 drvHostDSoundConstruct,
1685 /* pfnDestruct */
1686 drvHostDSoundDestruct,
1687 /* pfnRelocate */
1688 NULL,
1689 /* pfnIOCtl */
1690 NULL,
1691 /* pfnPowerOn */
1692 NULL,
1693 /* pfnReset */
1694 NULL,
1695 /* pfnSuspend */
1696 NULL,
1697 /* pfnResume */
1698 NULL,
1699 /* pfnAttach */
1700 NULL,
1701 /* pfnDetach */
1702 NULL,
1703 /* pfnPowerOff */
1704 NULL,
1705 /* pfnSoftReset */
1706 NULL,
1707 /* u32EndVersion */
1708 PDM_DRVREG_VERSION
1709};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette