7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * VBox audio devices: ALSA audio driver.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Copyright (C) 2006-2015 Oracle Corporation
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * available from http://www.virtualbox.org. This file is free software;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * you can redistribute it and/or modify it under the terms of the GNU
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * General Public License (GPL) as published by the Free Software
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * --------------------------------------------------------------------
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * This code is based on: alsaaudio.c
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * QEMU ALSA audio driver
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Copyright (c) 2005 Vassili Karpov (malc)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * of this software and associated documentation files (the "Software"), to deal
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * in the Software without restriction, including without limitation the rights
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * copies of the Software, and to permit persons to whom the Software is
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * furnished to do so, subject to the following conditions:
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * The above copyright notice and this permission notice shall be included in
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * all copies or substantial portions of the Software.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * THE SOFTWARE.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync/*******************************************************************************
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync* Header Files *
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync*******************************************************************************/
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync/* latency = period_size * periods / (rate * bytes_per_frame) */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioRecover(snd_pcm_t *phPCM);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Host Alsa audio driver instance data.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * @implements PDMIAUDIOCONNECTOR
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /** Pointer to the driver instance structure. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /** Pointer to host audio interface. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /** Error count for not flooding the release log.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * UINT32_MAX for unlimited logging. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioClose(snd_pcm_t **pphPCM)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Closing PCM descriptor failed: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic snd_pcm_format_t drvHostALSAAudioFmtToALSA(PDMAUDIOFMT fmt)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertMsgFailed(("Format %ld not supported\n", fmt));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioALSAToFmt(snd_pcm_format_t fmt,
10258d88c40d8254a2a0d89e9b6c1f3b487f5c2dvboxsync PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pEndianness is optional. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertMsgFailed(("Format %ld not supported\n", fmt));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioALSAGetShift(snd_pcm_format_t fmt, unsigned *puShift)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertMsgFailed(("Format %ld not supported\n", fmt));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioSetThreshold(snd_pcm_t *phPCM,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync int err = snd_pcm_sw_params_current(phPCM, pSWParms);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to get current software parameters for threshold: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_sw_params_set_start_threshold(phPCM, pSWParms, threshold);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set software threshold to %ld: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set new software parameters for threshold: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlowFunc(("Setting threshold to %RU32\n", threshold));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync const char *pszDev = fIn ? s_ALSAConf.pcm_name_in : s_ALSAConf.pcm_name_out;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Invalid or no %s device name set\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to open \"%s\" as %s: %s\n", pszDev,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to initialize hardware parameters: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_access(phPCM, pHWParms,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err)));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set audio format to %d: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set frequency to %dHz: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_period_time_near(phPCM, pHWParms,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set period time %d\n", pCfgReq->period_size));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pHWParms,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set buffer time %d\n", pCfgReq->buffer_size));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync snd_pcm_uframes_t period_size_f = (snd_pcm_uframes_t)period_size;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync snd_pcm_uframes_t buffer_size_f = (snd_pcm_uframes_t)buffer_size;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_get_period_size_min(pHWParms,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Could not determine minimal period size\n"));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Minimal period size is: %ld\n", minval));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Period size %RU32 is less than minimal period size %RU32\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Period size is: %RU32\n", period_size_f));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set period size %d (%s)\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* Calculate default buffer size here since it might have been changed
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * in the _near functions */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Could not retrieve minimal buffer size\n"));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Minimal buffer size is: %RU32\n", minval));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Buffer size %RU32 is less than minimal buffer size %RU32\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_set_buffer_size_near(phPCM,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Buffer size is: %RU32\n", buffer_size_f));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to set buffer size %d: %s\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to apply audio parameters\n"));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Freq=%dHz, period size=%RU32, buffer size=%RU32\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic void drvHostALSAAudioErrorHandler(const char *file, int line, const char *function,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /** @todo Implement me! */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertPtrReturn(pFramesAvail, VERR_INVALID_POINTER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioRecover(snd_pcm_t *phPCM)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic int drvHostALSAAudioStreamCtl(snd_pcm_t *phPCM, bool fPause)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioInit(PPDMIHOSTAUDIO pInterface)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to load the ALSA shared library, rc=%Rrc\n", rc));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync snd_lib_error_set_handler(drvHostALSAAudioErrorHandler);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlow(("No frames available, state=%d\n", state));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync size_t cbToRead = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
7b2cd67e9d38011fddd62967b7e9d26d88a28133vboxsync * Don't set error here because EAGAIN means there are no further frames
204c6779704e15c023bd6eda2d955be06bc486bevboxsync * available at the moment, try later. As we might have read some frames
7b2cd67e9d38011fddd62967b7e9d26d88a28133vboxsync * already these need to be processed instead.
7a26bb8055882cf73ea492e915d08f112dd25aa1vboxsync LogFunc(("Failed to read input frames: %s\n", snd_strerror(cRead)));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = audioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioGetAvail(pThisStrmOut->phPCM, &cAvail);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Error getting number of playback frames, rc=%Rrc\n", rc));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync drvAudioHstOutSamplesLive(pHstStrmOut, NULL /* pcStreamsLive */)));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync cbToRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail)));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = audioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvBuf, cbToRead, &cRead);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync cWritten = snd_pcm_writei(pThisStrmOut->phPCM, pThisStrmOut->pvBuf, cRead);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFunc(("Failed to write %RI32 frames\n", cRead));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* Stream was suspended and waiting for a recovery. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Failed to resume output stream\n"));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlowFunc(("Resumed suspended output stream\n"));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlowFunc(("Failed to write %RI32 output frames, rc=%Rrc\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync audioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioInitOut(PPDMIHOSTAUDIO pInterface,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync req.fmt = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioOpen(false /* false */, &req, &obt, &phPCM);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync size_t cbBuf = obt.samples * (1 << pHstStrmOut->Props.cShift);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Not enough memory for output DAC buffer (%RU32 samples, each %d bytes)\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync req.fmt = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(bool) drvHostALSAAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync return true; /* Always all enabled. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, false /* fStop */);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, true /* fStop */);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, false /* fStop */);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, true /* fStop */);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostALSAAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsyncstatic DECLCALLBACK(void) drvHostALSAAudioShutdown(PPDMIHOSTAUDIO pInterface)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Construct a DirectSound Audio driver instance.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * @copydoc FNPDMDRVCONSTRUCT
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsyncstatic DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Init the static parts.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* IBase */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync pDrvIns->IBase.pfnQueryInterface = drvHostALSAAudioQueryInterface;
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* IHostAudio */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync * Char driver registration record.
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* u32Version */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* szName */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "ALSAAudio",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* szRCMod */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* szR0Mod */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pszDescription */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "ALSA host audio driver",
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* fFlags */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* fClass. */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* cMaxInstances */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* cbInstance */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnConstruct */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnDestruct */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnRelocate */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnIOCtl */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnPowerOn */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnReset */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnSuspend */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnResume */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnAttach */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnDetach */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnPowerOff */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* pfnSoftReset */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync /* u32EndVersion */
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync {"DACSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_out,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync {"DACPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_out,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "DAC period size", &s_ALSAConf.period_size_out_overriden, 0},
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync {"DACBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_out,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "DAC buffer size", &s_ALSAConf.buffer_size_out_overriden, 0},
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync {"ADCSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_in,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync {"ADCPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_in,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "ADC period size", &s_ALSAConf.period_size_in_overriden, 0},
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync {"ADCBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_in,
7da9e7e719adde3baba3f6fa1d0bcfb170cf9911vboxsync "ADC buffer size", &s_ALSAConf.buffer_size_in_overriden, 0},