VirtualBox

Changeset 88455 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Apr 10, 2021 11:51:12 PM (4 years ago)
Author:
vboxsync
Message:

DrvHostAudioOss: Implemented draining (via thread). Implemented arbritrary buffer sizes. Bunch of cleanups. bugref:9890

File:
1 edited

Legend:

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

    r88413 r88455  
    4747#endif
    4848
    49 /** Makes DRVHOSTOSSAUDIO out of PDMIHOSTAUDIO. */
    50 #define PDMIHOSTAUDIO_2_DRVHOSTOSSAUDIO(pInterface) \
    51     ( (PDRVHOSTOSSAUDIO)((uintptr_t)pInterface - RT_UOFFSETOF(DRVHOSTOSSAUDIO, IHostAudio)) )
    52 
    5349
    5450/*********************************************************************************************************************************
     
    6258{
    6359    /** Pointer to the driver instance structure. */
    64     PPDMDRVINS         pDrvIns;
     60    PPDMDRVINS          pDrvIns;
    6561    /** Pointer to host audio interface. */
    66     PDMIHOSTAUDIO      IHostAudio;
     62    PDMIHOSTAUDIO       IHostAudio;
    6763    /** Error count for not flooding the release log.
    6864     *  UINT32_MAX for unlimited logging. */
    69     uint32_t           cLogErrors;
    70 } DRVHOSTOSSAUDIO, *PDRVHOSTOSSAUDIO;
    71 
     65    uint32_t            cLogErrors;
     66} DRVHOSTOSSAUDIO;
     67/** Pointer to the instance data for an OSS host audio driver. */
     68typedef DRVHOSTOSSAUDIO *PDRVHOSTOSSAUDIO;
     69
     70/**
     71 * OSS audio stream configuration.
     72 */
    7273typedef struct OSSAUDIOSTREAMCFG
    7374{
    74     PDMAUDIOPCMPROPS  Props;
    75     uint16_t          cFragments;
    76     uint32_t          cbFragmentSize;
    77 } OSSAUDIOSTREAMCFG, *POSSAUDIOSTREAMCFG;
    78 
     75    PDMAUDIOPCMPROPS    Props;
     76    uint16_t            cFragments;
     77    /** The log2 of cbFragment. */
     78    uint16_t            cbFragmentLog2;
     79    uint32_t            cbFragment;
     80} OSSAUDIOSTREAMCFG;
     81/** Pointer to an OSS audio stream configuration. */
     82typedef OSSAUDIOSTREAMCFG *POSSAUDIOSTREAMCFG;
     83
     84/**
     85 * OSS audio stream.
     86 */
    7987typedef struct OSSAUDIOSTREAM
    8088{
     89    /** The file descriptor. */
     90    int                 hFile;
     91    /** Buffer alignment. */
     92    uint8_t             uAlign;
     93    /** Set if we're draining the stream (output only). */
     94    bool                fDraining;
     95    /** Internal stream byte offset. */
     96    uint64_t            offInternal;
    8197    /** The stream's acquired configuration. */
    82     PPDMAUDIOSTREAMCFG pCfg;
    83     /** Buffer alignment. */
    84     uint8_t            uAlign;
    85     int                hFile;
    86     int                cFragments;
    87     int                cbFragmentSize;
    88     int                old_optr;
    89 } OSSAUDIOSTREAM, *POSSAUDIOSTREAM;
    90 
    91 typedef struct OSSAUDIOCFG
    92 {
    93     int nfrags;
    94     int fragsize;
    95     const char *devpath_out;
    96     const char *devpath_in;
    97     int debug;
    98 } OSSAUDIOCFG, *POSSAUDIOCFG;
    99 
    100 static OSSAUDIOCFG s_OSSConf =
    101 {
    102     4,
    103     4096,
    104     "/dev/dsp",
    105     "/dev/dsp",
    106     0
    107 };
    108 
    109 
    110 /* http://www.df.lth.se/~john_e/gems/gem002d.html */
    111 static uint32_t popcount(uint32_t u)
    112 {
    113     u = ((u&0x55555555) + ((u>>1)&0x55555555));
    114     u = ((u&0x33333333) + ((u>>2)&0x33333333));
    115     u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
    116     u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
    117     u = ( u&0x0000ffff) + (u>>16);
    118     return u;
    119 }
    120 
    121 
    122 static uint32_t lsbindex(uint32_t u)
    123 {
    124     return popcount((u & -u) - 1);
    125 }
     98    PDMAUDIOSTREAMCFG   Cfg;
     99    /** The acquired OSS configuration. */
     100    OSSAUDIOSTREAMCFG   OssCfg;
     101    /** Handle to the thread draining output streams. */
     102    RTTHREAD            hThreadDrain;
     103
     104} OSSAUDIOSTREAM;
     105/** Pointer to an OSS audio stream. */
     106typedef OSSAUDIOSTREAM *POSSAUDIOSTREAM;
     107
     108
     109/*********************************************************************************************************************************
     110*   Global Variables                                                                                                             *
     111*********************************************************************************************************************************/
     112/** The path to the output OSS device. */
     113static char g_szPathOutputDev[] = "/dev/dsp";
     114/** The path to the input OSS device. */
     115static char g_szPathInputDev[]  = "/dev/dsp";
     116
    126117
    127118
     
    320311     */
    321312    LogRel2(("OSS: Requested %RU16 %s fragments, %RU32 bytes each\n",
    322              pOSSReq->cFragments, fInput ? "input" : "output", pOSSReq->cbFragmentSize));
    323 
    324     int mmmmssss = (pOSSReq->cFragments << 16) | lsbindex(pOSSReq->cbFragmentSize);
     313             pOSSReq->cFragments, fInput ? "input" : "output", pOSSReq->cbFragment));
     314
     315    int mmmmssss = (pOSSReq->cFragments << 16) | pOSSReq->cbFragmentLog2;
    325316    AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss) >= 0,
    326317                          ("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s (%d)\n",
    327                            pOSSReq->cFragments, pOSSReq->cbFragmentSize, strerror(errno), errno),
     318                           pOSSReq->cFragments, pOSSReq->cbFragment, strerror(errno), errno),
    328319                          RTErrConvertFromErrno(errno));
    329320
     
    340331    if (RT_SUCCESS(rc))
    341332    {
    342         pOSSAcq->cFragments      = BufInfo.fragstotal;
    343         pOSSAcq->cbFragmentSize  = BufInfo.fragsize;
     333        pOSSAcq->cFragments     = BufInfo.fragstotal;
     334        pOSSAcq->cbFragment     = BufInfo.fragsize;
     335        pOSSAcq->cbFragmentLog2 = ASMBitFirstSetU32(BufInfo.fragsize) - 1;
     336        Assert(RT_BIT_32(pOSSAcq->cbFragmentLog2) == pOSSAcq->cbFragment);
    344337
    345338        LogRel2(("OSS: Got %RU16 %s fragments, %RU32 bytes each\n",
    346                  pOSSAcq->cFragments, fInput ? "input" : "output", pOSSAcq->cbFragmentSize));
     339                 pOSSAcq->cFragments, fInput ? "input" : "output", pOSSAcq->cbFragment));
    347340    }
    348341
     
    363356    AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
    364357
     358    pStreamOSS->hThreadDrain = NIL_RTTHREAD;
     359
    365360    /*
    366361     * Open the device
     
    368363    int rc;
    369364    if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    370         pStreamOSS->hFile = open(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK);
     365        pStreamOSS->hFile = open(g_szPathInputDev, O_RDONLY | O_NONBLOCK);
    371366    else
    372         pStreamOSS->hFile = open(s_OSSConf.devpath_out, O_WRONLY);
     367        pStreamOSS->hFile = open(g_szPathOutputDev, O_WRONLY);
    373368    if (pStreamOSS->hFile >= 0)
    374369    {
     
    380375
    381376        memcpy(&ReqOssCfg.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));
    382         ReqOssCfg.cFragments     = s_OSSConf.nfrags;
    383         ReqOssCfg.cbFragmentSize = s_OSSConf.fragsize;
    384 
    385         OSSAUDIOSTREAMCFG AcqOssCfg;
    386         RT_ZERO(AcqOssCfg);
    387         rc = ossStreamConfigure(pStreamOSS->hFile, pCfgReq->enmDir == PDMAUDIODIR_IN, &ReqOssCfg, &AcqOssCfg);
     377        ReqOssCfg.cbFragmentLog2 = 12;
     378        ReqOssCfg.cbFragment     = RT_BIT_32(ReqOssCfg.cbFragmentLog2);
     379        uint32_t const cbBuffer  = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
     380        ReqOssCfg.cFragments     = cbBuffer >> ReqOssCfg.cbFragmentLog2;
     381        AssertLogRelStmt(cbBuffer < ((uint32_t)0x7ffe << ReqOssCfg.cbFragmentLog2), ReqOssCfg.cFragments = 0x7ffe);
     382
     383        rc = ossStreamConfigure(pStreamOSS->hFile, pCfgReq->enmDir == PDMAUDIODIR_IN, &ReqOssCfg, &pStreamOSS->OssCfg);
    388384        if (RT_SUCCESS(rc))
    389385        {
     386            pStreamOSS->uAlign = 0; /** @todo r=bird: Where did the correct assignment of this go? */
     387
    390388            /*
    391389             * Complete the stream structure and fill in the pCfgAcq bits.
    392390             */
    393             if ((AcqOssCfg.cFragments * AcqOssCfg.cbFragmentSize) & pStreamOSS->uAlign)
     391            if ((pStreamOSS->OssCfg.cFragments * pStreamOSS->OssCfg.cbFragment) & pStreamOSS->uAlign)
    394392                LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n",
    395                         AcqOssCfg.cFragments * AcqOssCfg.cbFragmentSize, pStreamOSS->uAlign + 1));
    396 
    397             memcpy(&pCfgAcq->Props, &AcqOssCfg.Props, sizeof(PDMAUDIOPCMPROPS));
    398             pCfgAcq->Backend.cFramesPeriod     = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, AcqOssCfg.cbFragmentSize);
    399             pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */
    400             /** @todo Pre-buffering required? */
     393                        pStreamOSS->OssCfg.cFragments * pStreamOSS->OssCfg.cbFragment, pStreamOSS->uAlign + 1));
     394
     395            memcpy(&pCfgAcq->Props, &pStreamOSS->OssCfg.Props, sizeof(PDMAUDIOPCMPROPS));
     396            pCfgAcq->Backend.cFramesPeriod     = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamOSS->OssCfg.cbFragment);
     397            pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * pStreamOSS->OssCfg.cFragments;
     398            if (pCfgReq->enmDir == PDMAUDIODIR_OUT)
     399                pCfgAcq->Backend.cFramesPreBuffering = (uint64_t)pCfgReq->Backend.cFramesPreBuffering
     400                                                     * pCfgAcq->Backend.cFramesBufferSize
     401                                                     / RT_MAX(pCfgReq->Backend.cFramesBufferSize, 1);
     402            else
     403                pCfgAcq->Backend.cFramesPreBuffering = 0; /** @todo is this sane? */
    401404
    402405            /*
    403              * Duplicate the stream config and we're done!
     406             * Copy the stream config and we're done!
    404407             */
    405             pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);
    406             if (pStreamOSS->pCfg)
    407                 return VINF_SUCCESS;
    408 
    409             rc = VERR_NO_MEMORY;
     408            PDMAudioStrmCfgCopy(&pStreamOSS->Cfg, pCfgAcq);
     409            return VINF_SUCCESS;
    410410        }
    411411        ossStreamClose(&pStreamOSS->hFile);
     
    415415        rc = RTErrConvertFromErrno(errno);
    416416        LogRel(("OSS: Failed to open '%s': %s (%d) / %Rrc\n",
    417                 pCfgReq->enmDir == PDMAUDIODIR_IN ? s_OSSConf.devpath_in : s_OSSConf.devpath_out, strerror(errno), errno, rc));
     417                pCfgReq->enmDir == PDMAUDIODIR_IN ? g_szPathInputDev : g_szPathOutputDev, strerror(errno), errno, rc));
    418418    }
    419419    return rc;
     
    431431
    432432    ossStreamClose(&pStreamOSS->hFile);
    433     PDMAudioStrmCfgFree(pStreamOSS->pCfg);
    434     pStreamOSS->pCfg = NULL;
     433
     434    if (pStreamOSS->hThreadDrain != NIL_RTTHREAD)
     435    {
     436        int rc = RTThreadWait(pStreamOSS->hThreadDrain, 1, NULL);
     437        AssertRC(rc);
     438        pStreamOSS->hThreadDrain = NIL_RTTHREAD;
     439    }
    435440
    436441    return VINF_SUCCESS;
     
    438443
    439444
    440 static int ossControlStreamIn(/*PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd*/ void)
    441 {
    442     /** @todo Nothing to do here right now!? */
     445/**
     446 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
     447 */
     448static DECLCALLBACK(int) drvHostOssAudioHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     449{
     450    RT_NOREF(pInterface);
     451    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     452
     453    pStreamOSS->fDraining = false;
     454
     455    int rc;
     456    if (pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN)
     457        rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */
     458    else
     459    {
     460        int fMask = PCM_ENABLE_OUTPUT;
     461        if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0)
     462            rc = VINF_SUCCESS;
     463        else
     464        {
     465            LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno));
     466            rc = RTErrConvertFromErrno(errno);
     467        }
     468    }
     469
     470    LogFlowFunc(("returns %Rrc for '%s'\n", rc, pStreamOSS->Cfg.szName));
     471    return rc;
     472}
     473
     474
     475/**
     476 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
     477 */
     478static DECLCALLBACK(int) drvHostOssAudioHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     479{
     480    RT_NOREF(pInterface);
     481    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     482
     483    int rc;
     484    if (pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN)
     485        rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */
     486    else if (pStreamOSS->fDraining)
     487    {
     488        LogFlow(("Ignoring stream disable because we're draining...\n"));
     489        rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */
     490    }
     491    else
     492    {
     493        /** @todo Official documentation says this isn't the right way to stop playback.
     494         *        It may work in some implementations but fail in all others...  Suggest
     495         *        using SNDCTL_DSP_RESET / SNDCTL_DSP_HALT. */
     496        int fMask = 0;
     497        if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0)
     498            rc = VINF_SUCCESS;
     499        else
     500        {
     501            LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno));
     502            rc = RTErrConvertFromErrno(errno);
     503        }
     504    }
     505    LogFlowFunc(("returns %Rrc for '%s'\n", rc, pStreamOSS->Cfg.szName));
     506    return rc;
     507}
     508
     509
     510/**
     511 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
     512 */
     513static DECLCALLBACK(int) drvHostOssAudioHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     514{
     515    return drvHostOssAudioHA_StreamDisable(pInterface, pStream);
     516}
     517
     518
     519/**
     520 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
     521 */
     522static DECLCALLBACK(int) drvHostOssAudioHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     523{
     524    return drvHostOssAudioHA_StreamEnable(pInterface, pStream);
     525}
     526
     527
     528/**
     529 * @callback_method_impl{FNRTTHREAD,
     530 * Thread for calling SNDCTL_DSP_SYNC (blocking) on an output stream.}
     531 */
     532static DECLCALLBACK(int) drvHostOssAudioDrainThread(RTTHREAD ThreadSelf, void *pvUser)
     533{
     534    RT_NOREF(ThreadSelf);
     535    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pvUser;
     536    int rc;
     537
     538    /* Make it blocking (for Linux). */
     539    int fOrgFlags = fcntl(pStreamOSS->hFile, F_GETFL, 0);
     540    LogFunc(("F_GETFL -> %#x\n", fOrgFlags));
     541    Assert(fOrgFlags != -1);
     542    if (fOrgFlags != -1)
     543    {
     544        rc = fcntl(pStreamOSS->hFile, F_SETFL, fOrgFlags & ~O_NONBLOCK);
     545        AssertStmt(rc != -1, fOrgFlags = -1);
     546    }
     547
     548    /* Drain it. */
     549    LogFunc(("Calling SNDCTL_DSP_SYNC now...\n"));
     550    rc = ioctl(pStreamOSS->hFile, SNDCTL_DSP_SYNC, NULL);
     551    LogFunc(("SNDCTL_DSP_SYNC returned %d / errno=%d\n", rc, errno)); RT_NOREF(rc);
     552
     553    /* Re-enable non-blocking mode and disable it. */
     554    if (fOrgFlags != -1)
     555    {
     556        rc = fcntl(pStreamOSS->hFile, F_SETFL, fOrgFlags);
     557        Assert(rc != -1);
     558
     559        int fMask = 0;
     560        rc = ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask);
     561        Assert(rc >= 0);
     562
     563        pStreamOSS->fDraining = false;
     564        LogFunc(("Restored non-block mode and cleared the trigger mask\n"));
     565    }
    443566
    444567    return VINF_SUCCESS;
     
    446569
    447570
    448 static int ossControlStreamOut(POSSAUDIOSTREAM pStreamOSS, PDMAUDIOSTREAMCMD enmStreamCmd)
    449 {
    450     int rc = VINF_SUCCESS;
    451 
    452     switch (enmStreamCmd)
    453     {
    454         case PDMAUDIOSTREAMCMD_ENABLE:
    455         case PDMAUDIOSTREAMCMD_RESUME:
    456         {
    457             int mask = PCM_ENABLE_OUTPUT;
    458             if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
    459             {
    460                 LogRel(("OSS: Failed to enable output stream: %s\n", strerror(errno)));
    461                 rc = RTErrConvertFromErrno(errno);
    462             }
    463 
    464             break;
    465         }
    466 
    467         case PDMAUDIOSTREAMCMD_DISABLE:
    468         case PDMAUDIOSTREAMCMD_PAUSE:
    469         {
    470             int mask = 0;
    471             if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
    472             {
    473                 LogRel(("OSS: Failed to disable output stream: %s\n", strerror(errno)));
    474                 rc = RTErrConvertFromErrno(errno);
    475             }
    476 
    477             break;
    478         }
    479 
    480         default:
    481             rc = VERR_NOT_SUPPORTED;
    482             break;
    483     }
    484 
    485     return rc;
    486 }
     571/**
     572 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
     573 */
     574static DECLCALLBACK(int) drvHostOssAudioHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     575{
     576    PDRVHOSTOSSAUDIO pThis      = RT_FROM_MEMBER(pInterface, DRVHOSTOSSAUDIO, IHostAudio);
     577    POSSAUDIOSTREAM  pStreamOSS = (POSSAUDIOSTREAM)pStream;
     578    AssertReturn(pStreamOSS->Cfg.enmDir == PDMAUDIODIR_OUT, VERR_WRONG_ORDER);
     579
     580    pStreamOSS->fDraining = true;
     581
     582    /*
     583     * Because the SNDCTL_DSP_SYNC call is blocking on real OSS,
     584     * we kick off a thread to deal with it as we're probably on EMT
     585     * and cannot block for extended periods.
     586     */
     587    if (pStreamOSS->hThreadDrain != NIL_RTTHREAD)
     588    {
     589        int rc = RTThreadWait(pStreamOSS->hThreadDrain, 0, NULL);
     590        if (RT_SUCCESS(rc))
     591        {
     592            pStreamOSS->hThreadDrain = NIL_RTTHREAD;
     593            LogFunc(("Cleaned up stale thread handle.\n"));
     594        }
     595        else
     596        {
     597            LogFunc(("Drain thread already running (%Rrc).\n", rc));
     598            AssertMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     599            return rc == VERR_TIMEOUT ? VINF_SUCCESS : rc;
     600        }
     601    }
     602
     603    int rc = RTThreadCreateF(&pStreamOSS->hThreadDrain, drvHostOssAudioDrainThread, pStreamOSS, 0,
     604                             RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ossdrai%u", pThis->pDrvIns->iInstance);
     605    LogFunc(("Started drain thread: %Rrc\n", rc));
     606    AssertRCReturn(rc, rc);
     607
     608    return VINF_SUCCESS;
     609}
     610
    487611
    488612
     
    493617                                                         PDMAUDIOSTREAMCMD enmStreamCmd)
    494618{
    495     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    496     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    497 
    498     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    499 
    500     if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */
    501         return VINF_SUCCESS;
    502 
    503     int rc;
    504     if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN)
    505         rc = ossControlStreamIn(/*pInterface,  pStream, enmStreamCmd*/);
    506     else
    507         rc = ossControlStreamOut(pStreamOSS, enmStreamCmd);
    508 
    509     return rc;
     619    /** @todo r=bird: I'd like to get rid of this pfnStreamControl method,
     620     *        replacing it with individual StreamXxxx methods.  That would save us
     621     *        potentally huge switches and more easily see which drivers implement
     622     *        which operations (grep for pfnStreamXxxx). */
     623    switch (enmStreamCmd)
     624    {
     625        case PDMAUDIOSTREAMCMD_ENABLE:
     626            return drvHostOssAudioHA_StreamEnable(pInterface, pStream);
     627        case PDMAUDIOSTREAMCMD_DISABLE:
     628            return drvHostOssAudioHA_StreamDisable(pInterface, pStream);
     629        case PDMAUDIOSTREAMCMD_PAUSE:
     630            return drvHostOssAudioHA_StreamPause(pInterface, pStream);
     631        case PDMAUDIOSTREAMCMD_RESUME:
     632            return drvHostOssAudioHA_StreamResume(pInterface, pStream);
     633        case PDMAUDIOSTREAMCMD_DRAIN:
     634            return drvHostOssAudioHA_StreamDrain(pInterface, pStream);
     635            /** @todo the drain call for OSS is SNDCTL_DSP_SYNC, however in the non-ALSA
     636             *        implementation of OSS it is probably blocking.  Also, it comes with
     637             *        caveats about clicks and silence...  */
     638        case PDMAUDIOSTREAMCMD_END:
     639        case PDMAUDIOSTREAMCMD_32BIT_HACK:
     640        case PDMAUDIOSTREAMCMD_INVALID:
     641            /* no default*/
     642            break;
     643    }
     644    return VERR_NOT_SUPPORTED;
    510645}
    511646
     
    517652{
    518653    RT_NOREF(pInterface, pStream);
     654    Log4Func(("returns UINT32_MAX\n"));
    519655    return UINT32_MAX;
    520656}
     
    526662static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    527663{
     664    RT_NOREF(pInterface);
    528665    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    529666    AssertPtr(pStreamOSS);
    530     RT_NOREF(pInterface);
    531667
    532668    /*
     
    551687#endif
    552688
    553     return (uint32_t)(BufInfo.fragments * BufInfo.fragsize);
     689    uint32_t cbRet = (uint32_t)(BufInfo.fragments * BufInfo.fragsize);
     690    Log4Func(("returns %#x (%u)\n", cbRet, cbRet));
     691    return cbRet;
    554692}
    555693
     
    571709                                                      const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    572710{
     711    RT_NOREF(pInterface);
    573712    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    574713    AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
    575     RT_NOREF(pInterface);
    576714
    577715    /*
    578716     * Figure out now much to write.
    579717     */
    580     uint32_t cbToWrite;
    581718    audio_buf_info BufInfo;
    582719    int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &BufInfo);
     
    593730    }
    594731#endif
    595     cbToWrite = (unsigned)(BufInfo.fragments * BufInfo.fragsize);
     732    uint32_t cbToWrite = (uint32_t)(BufInfo.fragments * BufInfo.fragsize);
    596733    cbToWrite = RT_MIN(cbToWrite, cbBuf);
     734    Log3Func(("@%#RX64 cbBuf=%#x BufInfo: fragments=%#x fragstotal=%#x fragsize=%#x bytes=%#x %s cbToWrite=%#x\n",
     735              pStreamOSS->offInternal, cbBuf, BufInfo.fragments, BufInfo.fragstotal, BufInfo.fragsize, BufInfo.bytes,
     736              pStreamOSS->Cfg.szName, cbToWrite));
    597737
    598738    /*
     
    604744    while (cbChunk > 0)
    605745    {
    606         ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, (unsigned)s_OSSConf.fragsize));
    607         if (cbWritten >= 0)
     746        ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, pStreamOSS->OssCfg.cbFragment));
     747        if (cbWritten > 0)
    608748        {
    609749            AssertLogRelMsg(!(cbWritten & pStreamOSS->uAlign),
     
    613753            offChunk += (uint32_t)cbWritten;
    614754            cbChunk  -= (uint32_t)cbWritten;
     755            pStreamOSS->offInternal += cbWritten;
     756        }
     757        else if (cbWritten == 0)
     758        {
     759            LogFunc(("@%#RX64 write(%#x) returned zeroed (previously wrote %#x bytes)!\n",
     760                     pStreamOSS->offInternal, RT_MIN(cbChunk, pStreamOSS->OssCfg.cbFragment), cbWritten));
     761            break;
    615762        }
    616763        else
     
    621768    }
    622769
    623     *pcbWritten = cbToWrite;
     770    *pcbWritten = offChunk;
    624771    return VINF_SUCCESS;
    625772}
     
    630777 */
    631778static DECLCALLBACK(int) drvHostOssAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    632                                                          void *pvBuf, uint32_t uBufSize, uint32_t *puRead)
    633 {
     779                                                         void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     780{
     781    RT_NOREF(pInterface);
    634782    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    635783    AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
    636     RT_NOREF(pInterface);
    637 
    638 
    639     size_t cbToRead = uBufSize;
    640     LogFlowFunc(("cbToRead=%zi\n", cbToRead));
    641 
     784    Log3Func(("@%#RX64 cbBuf=%#x %s\n", pStreamOSS->offInternal, cbBuf, pStreamOSS->Cfg.szName));
     785
     786    size_t          cbToRead = cbBuf;
    642787    uint8_t * const pbDst    = (uint8_t *)pvBuf;
    643788    size_t          offWrite = 0;
     
    651796            cbToRead    -= cbRead;
    652797            offWrite    += cbRead;
     798            pStreamOSS->offInternal += cbRead;
    653799        }
    654800        else
     
    668814    }
    669815
    670     if (puRead)
    671         *puRead = offWrite;
     816    *pcbRead = offWrite;
    672817    return VINF_SUCCESS;
    673818}
     
    709854    /* IHostAudio */
    710855    pThis->IHostAudio.pfnGetConfig          = drvHostOssAudioHA_GetConfig;
     856    pThis->IHostAudio.pfnGetDevices         = NULL;
    711857    pThis->IHostAudio.pfnGetStatus          = drvHostOssAudioHA_GetStatus;
    712858    pThis->IHostAudio.pfnStreamCreate       = drvHostOssAudioHA_StreamCreate;
     
    718864    pThis->IHostAudio.pfnStreamPlay         = drvHostOssAudioHA_StreamPlay;
    719865    pThis->IHostAudio.pfnStreamCapture      = drvHostOssAudioHA_StreamCapture;
    720     pThis->IHostAudio.pfnGetDevices         = NULL;
    721866    pThis->IHostAudio.pfnStreamGetPending   = NULL;
    722867
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