diff options
Diffstat (limited to 'src/VBox/Devices/Audio/DrvHostNullAudio.cpp')
-rw-r--r-- | src/VBox/Devices/Audio/DrvHostNullAudio.cpp | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/src/VBox/Devices/Audio/DrvHostNullAudio.cpp b/src/VBox/Devices/Audio/DrvHostNullAudio.cpp new file mode 100644 index 00000000..aec4e022 --- /dev/null +++ b/src/VBox/Devices/Audio/DrvHostNullAudio.cpp @@ -0,0 +1,415 @@ +/* $Id: DrvHostNullAudio.cpp $ */ +/** @file + * NULL audio driver. + * + * This also acts as a fallback if no other backend is available. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * -------------------------------------------------------------------- + * + * This code is based on: noaudio.c QEMU based code. + * + * QEMU Timer based audio emulation + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/mem.h> +#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */ + +#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO +#include <VBox/log.h> +#include <VBox/vmm/pdmaudioifs.h> + +#include "DrvAudio.h" +#include "VBoxDD.h" + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct NULLAUDIOSTREAM +{ + /** The stream's acquired configuration. */ + PPDMAUDIOSTREAMCFG pCfg; +} NULLAUDIOSTREAM, *PNULLAUDIOSTREAM; + +/** + * NULL audio driver instance data. + * @implements PDMIAUDIOCONNECTOR + */ +typedef struct DRVHOSTNULLAUDIO +{ + /** Pointer to the driver instance structure. */ + PPDMDRVINS pDrvIns; + /** Pointer to host audio interface. */ + PDMIHOSTAUDIO IHostAudio; +} DRVHOSTNULLAUDIO, *PDRVHOSTNULLAUDIO; + + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig} + */ +static DECLCALLBACK(int) drvHostNullAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg) +{ + NOREF(pInterface); + AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER); + + RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "NULL audio driver"); + + pBackendCfg->cbStreamOut = sizeof(NULLAUDIOSTREAM); + pBackendCfg->cbStreamIn = sizeof(NULLAUDIOSTREAM); + + pBackendCfg->cMaxStreamsOut = 1; /* Output */ + pBackendCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */ + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnInit} + */ +static DECLCALLBACK(int) drvHostNullAudioInit(PPDMIHOSTAUDIO pInterface) +{ + NOREF(pInterface); + + LogFlowFuncLeaveRC(VINF_SUCCESS); + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown} + */ +static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface) +{ + RT_NOREF(pInterface); +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus} + */ +static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostNullAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir) +{ + RT_NOREF(enmDir); + AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN); + + return PDMAUDIOBACKENDSTS_RUNNING; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay} + */ +static DECLCALLBACK(int) drvHostNullAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + const void *pvBuf, uint32_t cxBuf, uint32_t *pcxWritten) +{ + AssertPtrReturn(pInterface, VERR_INVALID_POINTER); + AssertPtrReturn(pStream, VERR_INVALID_POINTER); + AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); + AssertReturn(cxBuf, VERR_INVALID_PARAMETER); + + RT_NOREF(pInterface, pStream, pvBuf); + + /* Note: No copying of samples needed here, as this a NULL backend. */ + + if (pcxWritten) + *pcxWritten = cxBuf; /* Return all bytes as written. */ + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture} + */ +static DECLCALLBACK(int) drvHostNullAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + void *pvBuf, uint32_t cxBuf, uint32_t *pcxRead) +{ + RT_NOREF(pInterface, pStream); + + PNULLAUDIOSTREAM pStreamNull = (PNULLAUDIOSTREAM)pStream; + + /* Return silence. */ + Assert(pStreamNull->pCfg); + DrvAudioHlpClearBuf(&pStreamNull->pCfg->Props, pvBuf, cxBuf, PDMAUDIOPCMPROPS_B2F(&pStreamNull->pCfg->Props, cxBuf)); + + if (pcxRead) + *pcxRead = cxBuf; + + return VINF_SUCCESS; +} + + +static int nullCreateStreamIn(PNULLAUDIOSTREAM pStreamNull, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) +{ + RT_NOREF(pStreamNull, pCfgReq, pCfgAcq); + + return VINF_SUCCESS; +} + + +static int nullCreateStreamOut(PNULLAUDIOSTREAM pStreamNull, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) +{ + RT_NOREF(pStreamNull, pCfgReq, pCfgAcq); + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} + */ +static DECLCALLBACK(int) drvHostNullAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) +{ + AssertPtrReturn(pInterface, VERR_INVALID_POINTER); + AssertPtrReturn(pStream, VERR_INVALID_POINTER); + AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); + AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); + + PNULLAUDIOSTREAM pStreamNull = (PNULLAUDIOSTREAM)pStream; + + int rc; + if (pCfgReq->enmDir == PDMAUDIODIR_IN) + rc = nullCreateStreamIn( pStreamNull, pCfgReq, pCfgAcq); + else + rc = nullCreateStreamOut(pStreamNull, pCfgReq, pCfgAcq); + + if (RT_SUCCESS(rc)) + { + pStreamNull->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq); + if (!pStreamNull->pCfg) + rc = VERR_NO_MEMORY; + } + + return rc; +} + + +static int nullDestroyStreamIn(void) +{ + LogFlowFuncLeaveRC(VINF_SUCCESS); + return VINF_SUCCESS; +} + + +static int nullDestroyStreamOut(PNULLAUDIOSTREAM pStreamNull) +{ + RT_NOREF(pStreamNull); + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} + */ +static DECLCALLBACK(int) drvHostNullAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) +{ + AssertPtrReturn(pInterface, VERR_INVALID_POINTER); + AssertPtrReturn(pStream, VERR_INVALID_POINTER); + + PNULLAUDIOSTREAM pStreamNull = (PNULLAUDIOSTREAM)pStream; + + if (!pStreamNull->pCfg) /* Not (yet) configured? Skip. */ + return VINF_SUCCESS; + + int rc; + if (pStreamNull->pCfg->enmDir == PDMAUDIODIR_IN) + rc = nullDestroyStreamIn(); + else + rc = nullDestroyStreamOut(pStreamNull); + + if (RT_SUCCESS(rc)) + { + DrvAudioHlpStreamCfgFree(pStreamNull->pCfg); + pStreamNull->pCfg = NULL; + } + + return rc; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl} + */ +static DECLCALLBACK(int) drvHostNullAudioStreamControl(PPDMIHOSTAUDIO pInterface, + PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd) +{ + RT_NOREF(pInterface, pStream, enmStreamCmd); + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable} + */ +static DECLCALLBACK(uint32_t) drvHostNullAudioStreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) +{ + RT_NOREF(pInterface, pStream); + + return UINT32_MAX; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable} + */ +static DECLCALLBACK(uint32_t) drvHostNullAudioStreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) +{ + RT_NOREF(pInterface, pStream); + + return UINT32_MAX; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus} + */ +static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostNullAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) +{ + RT_NOREF(pInterface, pStream); + return PDMAUDIOSTREAMSTS_FLAG_INITIALIZED | PDMAUDIOSTREAMSTS_FLAG_ENABLED; +} + + +/** + * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate} + */ +static DECLCALLBACK(int) drvHostNullAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) +{ + NOREF(pInterface); + NOREF(pStream); + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMIBASE,pfnQueryInterface} + */ +static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID) +{ + PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); + PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO); + + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio); + return NULL; +} + + +/** + * Constructs a Null audio driver instance. + * + * @copydoc FNPDMDRVCONSTRUCT + */ +static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) +{ + RT_NOREF(pCfg, fFlags); + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER); + /* pCfg is optional. */ + + PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO); + LogRel(("Audio: Initializing NULL driver\n")); + + /* + * Init the static parts. + */ + pThis->pDrvIns = pDrvIns; + /* IBase */ + pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface; + /* IHostAudio */ + PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio); + + return VINF_SUCCESS; +} + + +/** + * Char driver registration record. + */ +const PDMDRVREG g_DrvHostNullAudio = +{ + /* u32Version */ + PDM_DRVREG_VERSION, + /* szName */ + "NullAudio", + /* szRCMod */ + "", + /* szR0Mod */ + "", + /* pszDescription */ + "NULL audio host driver", + /* fFlags */ + PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT, + /* fClass. */ + PDM_DRVREG_CLASS_AUDIO, + /* cMaxInstances */ + ~0U, + /* cbInstance */ + sizeof(DRVHOSTNULLAUDIO), + /* pfnConstruct */ + drvHostNullAudioConstruct, + /* pfnDestruct */ + NULL, + /* pfnRelocate */ + NULL, + /* pfnIOCtl */ + NULL, + /* pfnPowerOn */ + NULL, + /* pfnReset */ + NULL, + /* pfnSuspend */ + NULL, + /* pfnResume */ + NULL, + /* pfnAttach */ + NULL, + /* pfnDetach */ + NULL, + /* pfnPowerOff */ + NULL, + /* pfnSoftReset */ + NULL, + /* u32EndVersion */ + PDM_DRVREG_VERSION +}; + |