DrvHostDSound.cpp revision 1705f7565ed8533058b8541d72d6c5d4453de00f
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * Windows host backend driver using DirectSound.
438e6decd0d482fcfb87e1e4bf41fb90d269e19and * Copyright (C) 2006-2015 Oracle Corporation
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * This file is part of VirtualBox Open Source Edition (OSE), as
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * available from http://www.virtualbox.org. This file is free software;
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * you can redistribute it and/or modify it under the terms of the GNU
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * General Public License (GPL) as published by the Free Software
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * Foundation, in version 2 as it comes in the "COPYING" file of the
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * --------------------------------------------------------------------
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * This code is based on: dsoundaudio.c
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * QEMU DirectSound audio driver
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * Copyright (c) 2005 Vassili Karpov (malc)
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * Permission is hereby granted, free of charge, to any person obtaining a copy
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * of this software and associated documentation files (the "Software"), to deal
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * in the Software without restriction, including without limitation the rights
ce3be1a0decfcb1819e10327a22e863491df68abniq * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * copies of the Software, and to permit persons to whom the Software is
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * furnished to do so, subject to the following conditions:
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * The above copyright notice and this permission notice shall be included in
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * all copies or substantial portions of the Software.
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * THE SOFTWARE.
d66ac514cc15e99228d72c56c6c3daf25da8d360niq#define DSLOGREL(a) \
d66ac514cc15e99228d72c56c6c3daf25da8d360niq } while (0)
d66ac514cc15e99228d72c56c6c3daf25da8d360niqtypedef struct DSOUNDHOSTCFG
e22cb12ff296f9a5984f79f11d3056dbb4277a4eniqtypedef struct DRVHOSTDSOUND
e22cb12ff296f9a5984f79f11d3056dbb4277a4eniq /** Pointer to the driver instance structure. */
65e7dfaf02b62ac316a7c762e5d19096936c77eeniq /** Pointer to host audio interface. */
65e7dfaf02b62ac316a7c762e5d19096936c77eeniq /** List of found host input devices. */
d66ac514cc15e99228d72c56c6c3daf25da8d360niq /** List of found host output devices. */
e22cb12ff296f9a5984f79f11d3056dbb4277a4eniq /** Configuration options. */
b733e063f126d953c241fecfa0678b7d208eb1e6ndtypedef struct DSOUNDSTREAMOUT
b733e063f126d953c241fecfa0678b7d208eb1e6ndtypedef struct DSOUNDSTREAMIN
d66ac514cc15e99228d72c56c6c3daf25da8d360niq * Callback context for enumeration callbacks
d66ac514cc15e99228d72c56c6c3daf25da8d360niqtypedef struct DSOUNDENUMCBCTX
d66ac514cc15e99228d72c56c6c3daf25da8d360niqtypedef struct DSOUNDDEV
d66ac514cc15e99228d72c56c6c3daf25da8d360niq/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
d66ac514cc15e99228d72c56c6c3daf25da8d360niq ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
ca62d95ec1b1c0ee9b09efad3fe218b3415b9236niqstatic size_t dsoundRingDistance(size_t offEnd, size_t offBegin, size_t cSize)
ca62d95ec1b1c0ee9b09efad3fe218b3415b9236niq return offEnd >= offBegin ? offEnd - offBegin: cSize - offBegin + offEnd;
ca62d95ec1b1c0ee9b09efad3fe218b3415b9236niqstatic int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
ca62d95ec1b1c0ee9b09efad3fe218b3415b9236niq pFmt->nAvgBytesPerSec = pCfg->uHz << (pCfg->cChannels == 2 ? 1: 0);
d66ac514cc15e99228d72c56c6c3daf25da8d360niq AssertMsgFailed(("Wave format %ld not supported\n", pCfg->enmFormat));
d66ac514cc15e99228d72c56c6c3daf25da8d360niq pDev = RTListGetFirst(&pThis->lstDevInput, DSOUNDDEV, Node);
d66ac514cc15e99228d72c56c6c3daf25da8d360niq pDev = RTListGetFirst(&pThis->lstDevOutput, DSOUNDDEV, Node);
d66ac514cc15e99228d72c56c6c3daf25da8d360niq DSLOGREL(("DSound: restore playback buffer %Rhrc\n", hr));
d66ac514cc15e99228d72c56c6c3daf25da8d360niq HRESULT hr = IDirectSoundBuffer_Unlock(pDSB, pv1, cb1, pv2, cb2);
d66ac514cc15e99228d72c56c6c3daf25da8d360niq DSLOG(("DSound: Unable to unlock output buffer, hr=%Rhrc\n", hr));
d66ac514cc15e99228d72c56c6c3daf25da8d360niqstatic int dsoundUnlockInput(LPDIRECTSOUNDCAPTUREBUFFER pDSCB,
d66ac514cc15e99228d72c56c6c3daf25da8d360niq HRESULT hr = IDirectSoundCaptureBuffer_Unlock(pDSCB, pv1, cb1, pv2, cb2);
d66ac514cc15e99228d72c56c6c3daf25da8d360niq DSLOG(("DSound: Unable to unlock input buffer, hr=%Rhrc\n", hr));
d66ac514cc15e99228d72c56c6c3daf25da8d360niqstatic int dsoundLockOutput(LPDIRECTSOUNDBUFFER pDSB, PDMPCMPROPS *pProps,
return VERR_INVALID_STATE;
return VINF_SUCCESS;
return VERR_ACCESS_DENIED;
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return rc;
DSLOG(("DSound: playback open csPlaybackBufferSize %d samples\n", pDSoundStrmOut->csPlaybackBufferSize));
return VINF_SUCCESS;
return VERR_NOT_SUPPORTED;
return rc;
return rc;
if (!pGUID)
case PDMAUDIORECSOURCE_MIC:
if (pDev)
return pGUID;
return VINF_SUCCESS;
return rc;
return rc;
cbReadPos = 0;
return VINF_SUCCESS;
return VERR_NOT_SUPPORTED;
if (!pDev)
return VERR_NO_MEMORY;
if (ppDev)
return rc;
if (pDev)
char *pszGUID;
return NULL;
static void dsoundLogDevice(const char *pszType, LPGUID lpGUID, LPCWSTR lpwstrDescription, LPCWSTR lpwstrModule)
if (!lpGUID)
return TRUE;
return TRUE;
if (!lpGUID)
return TRUE;
return TRUE;
if (pcSamples)
return rc;
switch (enmStreamCmd)
case PDMAUDIOSTREAMCMD_ENABLE:
return rc;
static DECLCALLBACK(int) drvHostDSoundPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
if (!pDSB)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
if (pcSamplesPlayed)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
if (pcSamplesPlayed)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
if (pcSamplesPlayed)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
int cbFree;
if (pcSamplesPlayed)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
if (pcSamplesPlayed)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
if (pcSamplesPlayed)
*pcSamplesPlayed = 0;
return VINF_SUCCESS;
if (cReadTotal)
if (pcSamplesPlayed)
return rc;
static DECLCALLBACK(int) drvHostDSoundFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
return VINF_SUCCESS;
if (pcSamples)
return rc;
static DECLCALLBACK(int) drvHostDSoundControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
switch (enmStreamCmd)
case PDMAUDIOSTREAMCMD_ENABLE:
return rc;
static DECLCALLBACK(int) drvHostDSoundCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
int rc;
*pcSamplesCaptured = 0;
return VINF_SUCCESS;
if (pcSamplesCaptured)
*pcSamplesCaptured = 0;
return VINF_SUCCESS;
DSLOG(("DSound: CaptureIn misaligned read position %d(%d)\n", cbReadPos, pHstStrmIn->Props.uAlign));
DWORD csCaptured = dsoundRingDistance(csReadPos, pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize);
if (csCaptured == 0)
if (pcSamplesCaptured)
*pcSamplesCaptured = 0;
return VINF_SUCCESS;
if (csMixFree == 0)
if (pcSamplesCaptured)
*pcSamplesCaptured = 0;
return VINF_SUCCESS;
LogFlow(("DSound: CaptureIn csMixFree = %d, csReadPos = %d, csCaptureReadPos = %d, csCaptured = %d\n",
if (pcSamplesCaptured)
*pcSamplesCaptured = 0;
return VINF_SUCCESS;
if (csWrittenTotal != 0)
&csProcessed);
pDSoundStrmIn->csCaptureReadPos = (pDSoundStrmIn->csCaptureReadPos + csProcessed) % pDSoundStrmIn->csCaptureBufferSize;
if (pcSamplesCaptured)
return rc;
static DECLCALLBACK(int) drvHostDSoundFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return NULL;
if (pszString)
return rc;
if (pszGuid)
return pGuid;
static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
return VERR_NOT_SUPPORTED;
return VINF_SUCCESS;
sizeof(DRVHOSTDSOUND),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,