VirtualBox

Changeset 62580 in vbox for trunk/src


Ignore:
Timestamp:
Jul 27, 2016 9:52:15 AM (8 years ago)
Author:
vboxsync
Message:

Audio: Initial commit of audio debug backend. This can dump the output streams to single .WAV files and also will later act as an input mockup object for testing input (capturing) audio data.

Location:
trunk/src/VBox
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r62327 r62580  
    21802180    PDM_DRVREG_CLASS_AUDIO,
    21812181    /* cMaxInstances */
    2182     2,
     2182    UINT32_MAX,
    21832183    /* cbInstance */
    21842184    sizeof(DRVAUDIO),
  • trunk/src/VBox/Devices/Audio/DrvAudio.h

    r62327 r62580  
    4848#include <iprt/circbuf.h>
    4949#include <iprt/critsect.h>
     50#include <iprt/file.h>
     51#include <iprt/path.h>
    5052
    5153#include <VBox/vmm/pdmdev.h>
     
    138140const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt);
    139141void DrvAudioHlpClearBuf(PPDMPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
     142uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels);
     143uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg);
    140144bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pPCMProps1, PPDMPCMPROPS pPCMProps2);
    141145bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg);
     
    147151PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt);
    148152
     153int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath);
     154int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType);
     155
     156int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMPCMPROPS pProps, PDMAUDIOFILEFLAGS fFlags);
     157int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile);
     158size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile);
     159int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags);
     160
     161#define AUDIO_MAKE_FOURCC(c0, c1, c2, c3) RT_H2LE_U32_C(RT_MAKE_U32_FROM_U8(c0, c1, c2, c3))
     162
    149163#endif /* DRV_AUDIO_H */
    150164
  • trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp

    r62372 r62580  
    4242 * THE SOFTWARE.
    4343 */
    44 #define LOG_GROUP LOG_GROUP_DRV_AUDIO
    45 #include <VBox/log.h>
     44#include <iprt/alloc.h>
    4645#include <iprt/asm-math.h>
    4746#include <iprt/assert.h>
     47#include <iprt/dir.h>
     48#include <iprt/file.h>
     49#include <iprt/string.h>
    4850#include <iprt/uuid.h>
    49 #include <iprt/string.h>
    50 #include <iprt/alloc.h>
    5151
    5252#include <VBox/vmm/pdmdev.h>
     
    6161#include "AudioMixBuffer.h"
    6262
     63#pragma pack(1)
     64/**
     65 * Structure for building up a .WAV file header.
     66 */
     67typedef struct AUDIOWAVFILEHDR
     68{
     69    uint32_t u32RIFF;
     70    uint32_t u32Size;
     71    uint32_t u32WAVE;
     72
     73    uint32_t u32Fmt;
     74    uint32_t u32Size1;
     75    uint16_t u16AudioFormat;
     76    uint16_t u16NumChannels;
     77    uint32_t u32SampleRate;
     78    uint32_t u32ByteRate;
     79    uint16_t u16BlockAlign;
     80    uint16_t u16BitsPerSample;
     81
     82    uint32_t u32ID2;
     83    uint32_t u32Size2;
     84} AUDIOWAVFILEHDR, *PAUDIOWAVFILEHDR;
     85#pragma pack()
     86
     87/**
     88 * Structure for keeeping the internal .WAV file data
     89 */
     90typedef struct AUDIOWAVFILEDATA
     91{
     92    /** The file header/footer. */
     93    AUDIOWAVFILEHDR Hdr;
     94} AUDIOWAVFILEDATA, *PAUDIOWAVFILEDATA;
    6395
    6496/**
     
    334366    bool fEqual =    pProps->uHz         == pCfg->uHz
    335367                  && pProps->cChannels   == pCfg->cChannels
     368                  && pProps->cbBitrate   == pCfg->cbBitrate
    336369                  && pProps->fSigned     == fSigned
    337370                  && pProps->cBits       == cBits
     
    345378    AssertPtrReturn(pProps2, false);
    346379
     380    if (pProps1 == pProps2)
     381        return true;
     382
    347383    return    pProps1->uHz         == pProps2->uHz
    348384           && pProps1->cChannels   == pProps2->cChannels
     385           && pProps1->cbBitrate   == pProps2->cbBitrate
    349386           && pProps1->fSigned     == pProps2->fSigned
    350387           && pProps1->cBits       == pProps2->cBits
     
    366403    pCfg->uHz           = pPCMProps->uHz;
    367404    pCfg->cChannels     = pPCMProps->cChannels;
     405    pCfg->cbBitrate     = DrvAudioHlpCalcBitrate(pPCMProps->cBits, pPCMProps->uHz, pPCMProps->cChannels) / 8;
    368406    pCfg->enmFormat     = DrvAudioAudFmtBitsToAudFmt(pPCMProps->cBits, pPCMProps->fSigned);
    369407
     
    401439    }
    402440
     441    fValid |= pCfg->uHz > 0;
    403442    /** @todo Check for defined frequencies supported. */
    404     fValid |= pCfg->uHz > 0;
     443    fValid |= pCfg->cbBitrate > 0;
    405444
    406445    return fValid;
     
    456495        pProps->cBits       = cBits;
    457496        pProps->fSigned     = fSigned;
     497        pProps->cShift      = (pCfg->cChannels == 2) + cShift;
    458498        pProps->cChannels   = pCfg->cChannels;
    459         pProps->cShift      = (pCfg->cChannels == 2) + cShift;
    460499        pProps->uAlign      = (1 << pProps->cShift) - 1;
    461         pProps->cbBitrate   = (pProps->cBits * pProps->uHz * pProps->cChannels) / 8;
     500        pProps->cbBitrate   = DrvAudioHlpCalcBitrate(pCfg) / 8;
    462501        pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
    463502    }
     
    497536    }
    498537
     538    LogFlow((", bitrate=%RU32", pCfg->cbBitrate));
     539
    499540    LogFlow((", endianness="));
    500541    switch (pCfg->enmEndianness)
     
    512553}
    513554
     555uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
     556{
     557    return (cBits * uHz * cChannels);
     558}
     559
     560uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg)
     561{
     562    return DrvAudioHlpCalcBitrate(DrvAudioHlpAudFmtToBits(pCfg->enmFormat), pCfg->uHz, pCfg->cChannels);
     563}
     564
     565/**
     566 * Sanitizes the file name component so that unsupported characters
     567 * will be replaced by an underscore ("_").
     568 *
     569 * @return  IPRT status code.
     570 * @param   pszPath             Path to sanitize.
     571 * @param   cbPath              Size (in bytes) of path to sanitize.
     572 */
     573int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath)
     574{
     575    int rc = VINF_SUCCESS;
     576#ifdef RT_OS_WINDOWS
     577    /* Filter out characters not allowed on Windows platforms, put in by
     578       RTTimeSpecToString(). */
     579    /** @todo Use something like RTPathSanitize() when available. Later. */
     580    RTUNICP aCpSet[] =
     581        { ' ', ' ', '(', ')', '-', '.', '0', '9', 'A', 'Z', 'a', 'z', '_', '_',
     582          0xa0, 0xd7af, '\0' };
     583    ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, aCpSet, '_' /* Replacement */);
     584    if (cReplaced < 0)
     585        rc = VERR_INVALID_UTF8_ENCODING;
     586#endif
     587    return rc;
     588}
     589
     590/**
     591 * Constructs an unique file name, based on the given path and the audio file type.
     592 *
     593 * @returns IPRT status code.
     594 * @param   pszFile             Where to store the constructed file name.
     595 * @param   cchFile             Size (in characters) of the file name buffer.
     596 * @param   pszPath             Base path to use.
     597 * @param   pszName             A name for better identifying the file. Optional.
     598 * @param   enmType             Audio file type to construct file name for.
     599 */
     600int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType)
     601{
     602    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
     603    AssertReturn(cchFile,    VERR_INVALID_PARAMETER);
     604    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     605    /* pszName is optional. */
     606
     607    int rc;
     608
     609    do
     610    {
     611        char szFilePath[RTPATH_MAX];
     612        size_t cchFilePath = RTStrPrintf(szFilePath, sizeof(szFilePath), "%s", pszPath);
     613
     614        /* Create it when necessary. */
     615        if (!RTDirExists(szFilePath))
     616        {
     617            rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
     618            if (RT_FAILURE(rc))
     619                break;
     620        }
     621
     622        /* The actually drop directory consist of the current time stamp and a
     623         * unique number when necessary. */
     624        char pszTime[64];
     625        RTTIMESPEC time;
     626        if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
     627        {
     628            rc = VERR_BUFFER_OVERFLOW;
     629            break;
     630        }
     631
     632        rc = DrvAudioHlpSanitizeFileName(pszTime, sizeof(pszTime));
     633        if (RT_FAILURE(rc))
     634            break;
     635
     636        rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszTime);
     637        if (RT_FAILURE(rc))
     638            break;
     639
     640        if (pszName) /* Optional name given? */
     641        {
     642            rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
     643            if (RT_FAILURE(rc))
     644                break;
     645
     646            rc = RTStrCat(szFilePath, sizeof(szFilePath), pszName);
     647            if (RT_FAILURE(rc))
     648                break;
     649        }
     650
     651        switch (enmType)
     652        {
     653            case PDMAUDIOFILETYPE_WAV:
     654                rc = RTStrCat(szFilePath, sizeof(szFilePath), ".wav");
     655                break;
     656
     657            default:
     658                AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
     659        }
     660
     661        if (RT_FAILURE(rc))
     662            break;
     663
     664        RTStrPrintf(pszFile, cchFile, "%s", szFilePath);
     665
     666    } while (0);
     667
     668    LogFlowFuncLeaveRC(rc);
     669    return rc;
     670}
     671
     672int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMPCMPROPS pProps,
     673                           PDMAUDIOFILEFLAGS fFlags)
     674{
     675    AssertPtrReturn(pFile,   VERR_INVALID_POINTER);
     676    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
     677    /** @todo Validate fOpen flags. */
     678    AssertPtrReturn(pProps,  VERR_INVALID_POINTER);
     679    /** @todo Validate fFlags flags. */
     680
     681    Assert(pProps->cChannels);
     682    Assert(pProps->uHz);
     683    Assert(pProps->cbBitrate);
     684    Assert(pProps->cBits);
     685
     686    pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
     687    if (!pFile->pvData)
     688        return VERR_NO_MEMORY;
     689    pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
     690
     691    PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
     692    AssertPtr(pData);
     693
     694    /* Header. */
     695    pData->Hdr.u32RIFF          = AUDIO_MAKE_FOURCC('R','I','F','F');
     696    pData->Hdr.u32Size          = 36;
     697    pData->Hdr.u32WAVE          = AUDIO_MAKE_FOURCC('W','A','V','E');
     698
     699    pData->Hdr.u32Fmt           = AUDIO_MAKE_FOURCC('f','m','t',' ');
     700    pData->Hdr.u32Size1         = 16; /* Means PCM. */
     701    pData->Hdr.u16AudioFormat   = 1;  /* PCM, linear quantization. */
     702    pData->Hdr.u16NumChannels   = pProps->cChannels;
     703    pData->Hdr.u32SampleRate    = pProps->uHz;
     704    pData->Hdr.u32ByteRate      = pProps->cbBitrate / 8;
     705    pData->Hdr.u16BlockAlign    = pProps->cChannels * pProps->cBits / 8;
     706    pData->Hdr.u16BitsPerSample = pProps->cBits;
     707
     708    /* Data chunk. */
     709    pData->Hdr.u32ID2           = AUDIO_MAKE_FOURCC('d','a','t','a');
     710    pData->Hdr.u32Size2         = 0;
     711
     712    int rc = RTFileOpen(&pFile->hFile, pszFile, fOpen);
     713    if (RT_SUCCESS(rc))
     714    {
     715        rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
     716        if (RT_FAILURE(rc))
     717        {
     718            RTFileClose(pFile->hFile);
     719            pFile->hFile = NIL_RTFILE;
     720        }
     721    }
     722
     723    if (RT_SUCCESS(rc))
     724    {
     725        pFile->enmType = PDMAUDIOFILETYPE_WAV;
     726
     727        RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
     728    }
     729    else
     730    {
     731        RTMemFree(pFile->pvData);
     732        pFile->pvData = NULL;
     733        pFile->cbData = 0;
     734    }
     735
     736    return rc;
     737}
     738
     739int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile)
     740{
     741    AssertPtrReturn(pFile, VERR_INVALID_POINTER);
     742
     743    Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
     744
     745    if (pFile->hFile != NIL_RTFILE)
     746    {
     747        PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
     748        AssertPtr(pData);
     749
     750        /* Update the header with the current data size. */
     751        RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
     752
     753        RTFileClose(pFile->hFile);
     754        pFile->hFile = NIL_RTFILE;
     755    }
     756
     757    if (pFile->pvData)
     758    {
     759        RTMemFree(pFile->pvData);
     760        pFile->pvData = NULL;
     761    }
     762
     763    pFile->cbData  = 0;
     764    pFile->enmType = PDMAUDIOFILETYPE_UNKNOWN;
     765
     766    return VINF_SUCCESS;
     767}
     768
     769size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile)
     770{
     771    AssertPtrReturn(pFile, VERR_INVALID_POINTER);
     772
     773    Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
     774
     775    PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
     776    AssertPtr(pData);
     777
     778    return pData->Hdr.u32Size2;
     779}
     780
     781int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
     782{
     783    AssertPtrReturn(pFile, VERR_INVALID_POINTER);
     784    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     785    /** @todo Validate fFlags. */
     786
     787    Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
     788
     789    if (!cbBuf)
     790        return VINF_SUCCESS;
     791
     792    PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
     793    AssertPtr(pData);
     794
     795    int rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
     796    if (RT_SUCCESS(rc))
     797    {
     798        pData->Hdr.u32Size  += (uint32_t)cbBuf;
     799        pData->Hdr.u32Size2 += (uint32_t)cbBuf;
     800    }
     801
     802    return rc;
     803}
     804
  • trunk/src/VBox/Devices/Makefile.kmk

    r62577 r62580  
    548548        Audio/DrvHostNullAudio.cpp
    549549
     550 ifdef VBOX_WITH_AUDIO_DEBUG
     551  VBoxDD_DEFS    += VBOX_WITH_AUDIO_DEBUG
     552  VBoxDD_SOURCES += \
     553        Audio/DrvHostDebugAudio.cpp
     554 endif
     555
    550556 ifeq ($(KBUILD_TARGET),darwin)
    551557  VBoxDD_SOURCES += \
  • trunk/src/VBox/Devices/build/VBoxDD.cpp

    r62516 r62580  
    275275    if (RT_FAILURE(rc))
    276276        return rc;
     277#ifdef VBOX_WITH_AUDIO_DEBUG
     278    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostDebugAudio);
     279    if (RT_FAILURE(rc))
     280        return rc;
     281#endif
    277282    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostNullAudio);
    278283    if (RT_FAILURE(rc))
  • trunk/src/VBox/Devices/build/VBoxDD.h

    r62056 r62580  
    118118extern const PDMDRVREG g_DrvNetSniffer;
    119119extern const PDMDRVREG g_DrvAUDIO;
     120#ifdef VBOX_WITH_AUDIO_DEBUG
     121extern const PDMDRVREG g_DrvHostDebugAudio;
     122#endif
    120123extern const PDMDRVREG g_DrvHostNullAudio;
    121124#if defined(RT_OS_WINDOWS)
  • trunk/src/VBox/Main/Makefile.kmk

    r62577 r62580  
    274274        $(if $(VBOX_WITH_ALSA),VBOX_WITH_ALSA,) \
    275275        $(if $(VBOX_WITH_PULSE),VBOX_WITH_PULSE,) \
     276        $(if $(VBOX_WITH_AUDIO_DEBUG),VBOX_WITH_AUDIO_DEBUG,) \
    276277        $(if $(VBOX_WITH_VRDE_AUDIO),VBOX_WITH_VRDE_AUDIO,) \
    277278        $(if $(VBOX_WITH_E1000),VBOX_WITH_E1000,) \
  • trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp

    r62379 r62580  
    29232923            InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVRDE);
    29242924            InsertConfigInteger(pCfg, "ObjectVRDPServer", (uintptr_t)mConsoleVRDPServer);
     2925#endif
     2926
     2927#ifdef VBOX_WITH_AUDIO_DEBUG
     2928            InsertConfigNode(pInst, "LUN#2", &pLunL1);
     2929            InsertConfigString(pLunL1, "Driver", "AUDIO");
     2930
     2931            InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
     2932            InsertConfigString(pLunL1, "Driver", "DebugAudio");
     2933
     2934            InsertConfigNode(pLunL1, "Config", &pCfg);
     2935            InsertConfigString(pCfg, "AudioDriver", "DebugAudio");
     2936            InsertConfigString(pCfg, "StreamName", bstr);
    29252937#endif
    29262938            /** @todo Add audio video recording driver here. */
Note: See TracChangeset for help on using the changeset viewer.

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