VirtualBox

Ignore:
Timestamp:
Mar 25, 2021 11:29:10 AM (4 years ago)
Author:
vboxsync
Message:

DrvHostAudioOss: More natural function ordering within the file. Some cleanups. bugref:9890

File:
1 edited

Legend:

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

    r88288 r88289  
    122122static uint32_t lsbindex(uint32_t u)
    123123{
    124     return popcount ((u&-u)-1);
     124    return popcount((u & -u) - 1);
    125125}
    126126
     
    170170    if (close(*phFile))
    171171    {
    172         LogRel(("OSS: Closing stream failed: %s\n", strerror(errno)));
    173         rc = VERR_GENERAL_FAILURE; /** @todo */
     172        rc = RTErrConvertFromErrno(errno);
     173        LogRel(("OSS: Closing stream failed: %s / %Rrc\n", strerror(errno), rc));
    174174    }
    175175    else
     
    180180
    181181    return rc;
     182}
     183
     184
     185/**
     186 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
     187 */
     188static DECLCALLBACK(int) drvHostOssAudioHA_Init(PPDMIHOSTAUDIO pInterface)
     189{
     190    RT_NOREF(pInterface);
     191
     192    return VINF_SUCCESS;
     193}
     194
     195
     196/**
     197 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
     198 */
     199static DECLCALLBACK(void) drvHostOssAudioHA_Shutdown(PPDMIHOSTAUDIO pInterface)
     200{
     201    RT_NOREF(pInterface);
     202}
     203
     204
     205/**
     206 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
     207 */
     208static DECLCALLBACK(int) drvHostOssAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
     209{
     210    RT_NOREF(pInterface);
     211
     212    RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "OSS");
     213
     214    pBackendCfg->cbStreamIn  = sizeof(OSSAUDIOSTREAM);
     215    pBackendCfg->cbStreamOut = sizeof(OSSAUDIOSTREAM);
     216
     217    int hFile = open("/dev/dsp", O_WRONLY | O_NONBLOCK, 0);
     218    if (hFile == -1)
     219    {
     220        /* Try opening the mixing device instead. */
     221        hFile = open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0);
     222    }
     223    if (hFile != -1)
     224    {
     225        int ossVer = -1;
     226        int err = ioctl(hFile, OSS_GETVERSION, &ossVer);
     227        if (err == 0)
     228        {
     229            LogRel2(("OSS: Using version: %d\n", ossVer));
     230#ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
     231            oss_sysinfo ossInfo;
     232            RT_ZERO(ossInfo);
     233            err = ioctl(hFile, OSS_SYSINFO, &ossInfo);
     234            if (err == 0)
     235            {
     236                LogRel2(("OSS: Number of DSPs: %d\n", ossInfo.numaudios));
     237                LogRel2(("OSS: Number of mixers: %d\n", ossInfo.nummixers));
     238
     239                int cDev = ossInfo.nummixers;
     240                if (!cDev)
     241                    cDev = ossInfo.numaudios;
     242
     243                pBackendCfg->cMaxStreamsIn   = UINT32_MAX;
     244                pBackendCfg->cMaxStreamsOut  = UINT32_MAX;
     245            }
     246            else
     247#endif
     248            {
     249                /* Since we cannot query anything, assume that we have at least
     250                 * one input and one output if we found "/dev/dsp" or "/dev/mixer". */
     251
     252                pBackendCfg->cMaxStreamsIn   = UINT32_MAX;
     253                pBackendCfg->cMaxStreamsOut  = UINT32_MAX;
     254            }
     255        }
     256        else
     257            LogRel(("OSS: Unable to determine installed version: %s (%d)\n", strerror(err), err));
     258        close(hFile);
     259    }
     260    else
     261        LogRel(("OSS: No devices found, audio is not available\n"));
     262
     263    return VINF_SUCCESS;
     264}
     265
     266
     267
     268
     269/**
     270 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
     271 */
     272static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostOssAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
     273{
     274    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
     275    RT_NOREF(enmDir);
     276
     277    return PDMAUDIOBACKENDSTS_RUNNING;
    182278}
    183279
     
    293389
    294390
     391static int ossCreateStreamIn(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     392{
     393    int rc;
     394
     395    int hFile = -1;
     396
     397    do
     398    {
     399        OSSAUDIOSTREAMCFG ossReq;
     400        memcpy(&ossReq.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));
     401
     402        ossReq.cFragments     = s_OSSConf.nfrags;
     403        ossReq.cbFragmentSize = s_OSSConf.fragsize;
     404
     405        OSSAUDIOSTREAMCFG ossAcq;
     406        RT_ZERO(ossAcq);
     407
     408        rc = ossStreamOpen(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK, &ossReq, &ossAcq, &hFile);
     409        if (RT_SUCCESS(rc))
     410        {
     411            memcpy(&pCfgAcq->Props, &ossAcq.Props, sizeof(PDMAUDIOPCMPROPS));
     412
     413            if (ossAcq.cFragments * ossAcq.cbFragmentSize & pStreamOSS->uAlign)
     414            {
     415                LogRel(("OSS: Warning: Misaligned capturing buffer: Size = %zu, Alignment = %u\n",
     416                        ossAcq.cFragments * ossAcq.cbFragmentSize, pStreamOSS->uAlign + 1));
     417            }
     418
     419            if (RT_SUCCESS(rc))
     420            {
     421                pStreamOSS->hFile = hFile;
     422
     423                pCfgAcq->Backend.cFramesPeriod     = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, ossAcq.cbFragmentSize);
     424                pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering". */
     425                /** @todo Pre-buffering required? */
     426            }
     427        }
     428
     429    } while (0);
     430
     431    if (RT_FAILURE(rc))
     432        ossStreamClose(&hFile);
     433
     434    LogFlowFuncLeaveRC(rc);
     435    return rc;
     436}
     437
     438
     439static int ossCreateStreamOut(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     440{
     441    OSSAUDIOSTREAMCFG reqStream;
     442    RT_ZERO(reqStream);
     443
     444    memcpy(&reqStream.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));
     445    reqStream.cFragments     = s_OSSConf.nfrags;
     446    reqStream.cbFragmentSize = s_OSSConf.fragsize;
     447
     448    OSSAUDIOSTREAMCFG obtStream;
     449    RT_ZERO(obtStream);
     450
     451    int hFile = -1;
     452    int rc = ossStreamOpen(s_OSSConf.devpath_out, O_WRONLY, &reqStream, &obtStream, &hFile);
     453    if (RT_SUCCESS(rc))
     454    {
     455        memcpy(&pCfgAcq->Props, &obtStream.Props, sizeof(PDMAUDIOPCMPROPS));
     456
     457        if ((obtStream.cFragments * obtStream.cbFragmentSize) & pStreamOSS->uAlign)
     458            LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n",
     459                    obtStream.cFragments * obtStream.cbFragmentSize, pStreamOSS->uAlign + 1));
     460
     461        pStreamOSS->hFile = hFile;
     462
     463        pCfgAcq->Backend.cFramesPeriod     = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, obtStream.cbFragmentSize);
     464        pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */
     465
     466    }
     467
     468    LogFlowFuncLeaveRC(rc);
     469    return rc;
     470}
     471
     472
     473/**
     474 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
     475 */
     476static DECLCALLBACK(int) drvHostOssAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     477                                                        PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     478{
     479    AssertPtr(pInterface);
     480    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     481    AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
     482    AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
     483    AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
     484
     485    pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);
     486    AssertReturn(pStreamOSS->pCfg, VERR_NO_MEMORY);
     487
     488    int rc;
     489    if (pCfgReq->enmDir == PDMAUDIODIR_IN)
     490        rc = ossCreateStreamIn( pStreamOSS, pCfgReq, pCfgAcq);
     491    else
     492        rc = ossCreateStreamOut(pStreamOSS, pCfgReq, pCfgAcq);
     493
     494    if (RT_FAILURE(rc))
     495    {
     496        PDMAudioStrmCfgFree(pStreamOSS->pCfg);
     497        pStreamOSS->pCfg = NULL;
     498    }
     499    return rc;
     500}
     501
     502
     503/**
     504 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
     505 */
     506static DECLCALLBACK(int) drvHostOssAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     507{
     508    RT_NOREF(pInterface);
     509    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     510    AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
     511
     512    ossStreamClose(&pStreamOSS->hFile);
     513    PDMAudioStrmCfgFree(pStreamOSS->pCfg);
     514    pStreamOSS->pCfg = NULL;
     515
     516    return VINF_SUCCESS;
     517}
     518
     519
    295520static int ossControlStreamIn(/*PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd*/ void)
    296521{
     
    345570
    346571/**
    347  * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
    348  */
    349 static DECLCALLBACK(int) drvHostOssAudioHA_Init(PPDMIHOSTAUDIO pInterface)
    350 {
     572 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
     573 */
     574static DECLCALLBACK(int) drvHostOssAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     575                                                         PDMAUDIOSTREAMCMD enmStreamCmd)
     576{
     577    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     578    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     579
     580    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     581
     582    if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */
     583        return VINF_SUCCESS;
     584
     585    int rc;
     586    if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN)
     587        rc = ossControlStreamIn(/*pInterface,  pStream, enmStreamCmd*/);
     588    else
     589        rc = ossControlStreamOut(pStreamOSS, enmStreamCmd);
     590
     591    return rc;
     592}
     593
     594
     595/**
     596 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
     597 */
     598static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     599{
     600    RT_NOREF(pInterface, pStream);
     601    return UINT32_MAX;
     602}
     603
     604
     605/**
     606 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
     607 */
     608static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     609{
     610    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     611    AssertPtr(pStreamOSS);
    351612    RT_NOREF(pInterface);
    352613
     614    /*
     615     * Note! This logic was found in StreamPlay and corrected a little.
     616     *
     617     * The logic here must match what StreamPlay does.
     618     */
     619    audio_buf_info abinfo = { 0, 0, 0, 0 };
     620    int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
     621    AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0);
     622
     623#if 0 /** @todo we could return abinfo.bytes here iff StreamPlay didn't use the fragmented approach */
     624    /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */
     625    AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3);
     626    if ((unsigned)abinfo.bytes > cbBuf)
     627    {
     628        LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf));
     629        abinfo.bytes = cbBuf;
     630        /* Keep going. */
     631    }
     632#endif
     633
     634    return (uint32_t)(abinfo.fragments * abinfo.fragsize);
     635}
     636
     637
     638/**
     639 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
     640 */
     641static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostOssAudioHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     642{
     643    RT_NOREF(pInterface, pStream);
     644    return PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED;
     645}
     646
     647
     648/**
     649 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
     650 */
     651static DECLCALLBACK(int) drvHostOssAudioHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     652{
     653    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     654    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     655
     656    LogFlowFuncEnter();
     657
     658    /* Nothing to do here for OSS. */
     659    return VINF_SUCCESS;
     660}
     661
     662
     663/**
     664 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
     665 */
     666static DECLCALLBACK(int) drvHostOssAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     667                                                      const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     668{
     669    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
     670    AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
     671    RT_NOREF(pInterface);
     672
     673    /*
     674     * Figure out now much to write.
     675     */
     676    uint32_t cbToWrite;
     677    audio_buf_info abinfo;
     678    int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
     679    AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno),
     680                          RTErrConvertFromErrno(errno));
     681
     682#if 0   /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */
     683    AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3);
     684    if ((unsigned)abinfo.bytes > cbBuf)
     685    {
     686        LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf));
     687        abinfo.bytes = cbBuf;
     688        /* Keep going. */
     689    }
     690#endif
     691    cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize);
     692    cbToWrite = RT_MIN(cbToWrite, cbBuf);
     693
     694    /*
     695     * Write.
     696     */
     697    uint8_t const *pbBuf    = (uint8_t const *)pvBuf;
     698    uint32_t       cbChunk  = cbToWrite;
     699    uint32_t       offChunk = 0;
     700    while (cbChunk > 0)
     701    {
     702        ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, (unsigned)s_OSSConf.fragsize));
     703        if (cbWritten >= 0)
     704        {
     705            AssertLogRelMsg(!(cbWritten & pStreamOSS->uAlign),
     706                            ("OSS: Misaligned write (written %#zx, alignment %#x)\n", cbWritten, pStreamOSS->uAlign));
     707
     708            Assert((uint32_t)cbWritten <= cbChunk);
     709            offChunk += (uint32_t)cbWritten;
     710            cbChunk  -= (uint32_t)cbWritten;
     711        }
     712        else
     713        {
     714            LogRel(("OSS: Failed writing output data: %s (%d)\n", strerror(errno), errno));
     715            return RTErrConvertFromErrno(errno);
     716        }
     717    }
     718
     719    *pcbWritten = cbToWrite;
    353720    return VINF_SUCCESS;
    354721}
     
    403770
    404771
    405 static int ossDestroyStreamIn(PPDMAUDIOBACKENDSTREAM pStream)
    406 {
    407     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    408 
    409     LogFlowFuncEnter();
    410 
    411     ossStreamClose(&pStreamOSS->hFile);
    412 
    413     return VINF_SUCCESS;
    414 }
    415 
    416 
    417 static int ossDestroyStreamOut(PPDMAUDIOBACKENDSTREAM pStream)
    418 {
    419     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    420 
    421     ossStreamClose(&pStreamOSS->hFile);
    422 
    423     return VINF_SUCCESS;
    424 }
    425 
    426 
    427 /**
    428  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
    429  */
    430 static DECLCALLBACK(int) drvHostOssAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
    431 {
    432     RT_NOREF(pInterface);
    433 
    434     RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "OSS");
    435 
    436     pBackendCfg->cbStreamIn  = sizeof(OSSAUDIOSTREAM);
    437     pBackendCfg->cbStreamOut = sizeof(OSSAUDIOSTREAM);
    438 
    439     int hFile = open("/dev/dsp", O_WRONLY | O_NONBLOCK, 0);
    440     if (hFile == -1)
    441     {
    442         /* Try opening the mixing device instead. */
    443         hFile = open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0);
    444     }
    445 
    446     int ossVer = -1;
    447 
    448 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
    449     oss_sysinfo ossInfo;
    450     RT_ZERO(ossInfo);
    451 #endif
    452 
    453     if (hFile != -1)
    454     {
    455         int err = ioctl(hFile, OSS_GETVERSION, &ossVer);
    456         if (err == 0)
    457         {
    458             LogRel2(("OSS: Using version: %d\n", ossVer));
    459 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
    460             err = ioctl(hFile, OSS_SYSINFO, &ossInfo);
    461             if (err == 0)
    462             {
    463                 LogRel2(("OSS: Number of DSPs: %d\n", ossInfo.numaudios));
    464                 LogRel2(("OSS: Number of mixers: %d\n", ossInfo.nummixers));
    465 
    466                 int cDev = ossInfo.nummixers;
    467                 if (!cDev)
    468                     cDev = ossInfo.numaudios;
    469 
    470                 pBackendCfg->cMaxStreamsIn   = UINT32_MAX;
    471                 pBackendCfg->cMaxStreamsOut  = UINT32_MAX;
    472             }
    473             else
    474             {
    475 #endif
    476                 /* Since we cannot query anything, assume that we have at least
    477                  * one input and one output if we found "/dev/dsp" or "/dev/mixer". */
    478 
    479                 pBackendCfg->cMaxStreamsIn   = UINT32_MAX;
    480                 pBackendCfg->cMaxStreamsOut  = UINT32_MAX;
    481 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
    482             }
    483 #endif
    484         }
    485         else
    486             LogRel(("OSS: Unable to determine installed version: %s (%d)\n", strerror(err), err));
    487     }
    488     else
    489         LogRel(("OSS: No devices found, audio is not available\n"));
    490 
    491     if (hFile != -1)
    492         close(hFile);
    493 
    494     return VINF_SUCCESS;
    495 }
    496 
    497 
    498 static int ossCreateStreamIn(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    499 {
    500     int rc;
    501 
    502     int hFile = -1;
    503 
    504     do
    505     {
    506         OSSAUDIOSTREAMCFG ossReq;
    507         memcpy(&ossReq.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));
    508 
    509         ossReq.cFragments     = s_OSSConf.nfrags;
    510         ossReq.cbFragmentSize = s_OSSConf.fragsize;
    511 
    512         OSSAUDIOSTREAMCFG ossAcq;
    513         RT_ZERO(ossAcq);
    514 
    515         rc = ossStreamOpen(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK, &ossReq, &ossAcq, &hFile);
    516         if (RT_SUCCESS(rc))
    517         {
    518             memcpy(&pCfgAcq->Props, &ossAcq.Props, sizeof(PDMAUDIOPCMPROPS));
    519 
    520             if (ossAcq.cFragments * ossAcq.cbFragmentSize & pStreamOSS->uAlign)
    521             {
    522                 LogRel(("OSS: Warning: Misaligned capturing buffer: Size = %zu, Alignment = %u\n",
    523                         ossAcq.cFragments * ossAcq.cbFragmentSize, pStreamOSS->uAlign + 1));
    524             }
    525 
    526             if (RT_SUCCESS(rc))
    527             {
    528                 pStreamOSS->hFile = hFile;
    529 
    530                 pCfgAcq->Backend.cFramesPeriod     = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, ossAcq.cbFragmentSize);
    531                 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering". */
    532                 /** @todo Pre-buffering required? */
    533             }
    534         }
    535 
    536     } while (0);
    537 
    538     if (RT_FAILURE(rc))
    539         ossStreamClose(&hFile);
    540 
    541     LogFlowFuncLeaveRC(rc);
    542     return rc;
    543 }
    544 
    545 
    546 static int ossCreateStreamOut(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    547 {
    548     OSSAUDIOSTREAMCFG reqStream;
    549     RT_ZERO(reqStream);
    550 
    551     memcpy(&reqStream.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));
    552     reqStream.cFragments     = s_OSSConf.nfrags;
    553     reqStream.cbFragmentSize = s_OSSConf.fragsize;
    554 
    555     OSSAUDIOSTREAMCFG obtStream;
    556     RT_ZERO(obtStream);
    557 
    558     int hFile = -1;
    559     int rc = ossStreamOpen(s_OSSConf.devpath_out, O_WRONLY, &reqStream, &obtStream, &hFile);
    560     if (RT_SUCCESS(rc))
    561     {
    562         memcpy(&pCfgAcq->Props, &obtStream.Props, sizeof(PDMAUDIOPCMPROPS));
    563 
    564         if ((obtStream.cFragments * obtStream.cbFragmentSize) & pStreamOSS->uAlign)
    565             LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n",
    566                     obtStream.cFragments * obtStream.cbFragmentSize, pStreamOSS->uAlign + 1));
    567 
    568         pStreamOSS->hFile = hFile;
    569 
    570         pCfgAcq->Backend.cFramesPeriod     = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, obtStream.cbFragmentSize);
    571         pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */
    572 
    573     }
    574 
    575     LogFlowFuncLeaveRC(rc);
    576     return rc;
    577 }
    578 
    579 
    580 /**
    581  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
    582  */
    583 static DECLCALLBACK(int) drvHostOssAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    584                                                       const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    585 {
    586     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    587     AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
    588     RT_NOREF(pInterface);
    589 
    590     /*
    591      * Figure out now much to write.
    592      */
    593     uint32_t cbToWrite;
    594     audio_buf_info abinfo;
    595     int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
    596     AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno),
    597                           RTErrConvertFromErrno(errno));
    598 
    599 #if 0   /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */
    600     AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3);
    601     if ((unsigned)abinfo.bytes > cbBuf)
    602     {
    603         LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf));
    604         abinfo.bytes = cbBuf;
    605         /* Keep going. */
    606     }
    607 #endif
    608     cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize);
    609     cbToWrite = RT_MIN(cbToWrite, cbBuf);
    610 
    611     /*
    612      * Write.
    613      */
    614     uint8_t const *pbBuf    = (uint8_t const *)pvBuf;
    615     uint32_t       cbChunk  = cbToWrite;
    616     uint32_t       offChunk = 0;
    617     while (cbChunk > 0)
    618     {
    619         ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, (unsigned)s_OSSConf.fragsize));
    620         if (cbWritten >= 0)
    621         {
    622             AssertLogRelMsg(!(cbWritten & pStreamOSS->uAlign),
    623                             ("OSS: Misaligned write (written %#zx, alignment %#x)\n", cbWritten, pStreamOSS->uAlign));
    624 
    625             Assert((uint32_t)cbWritten <= cbChunk);
    626             offChunk += (uint32_t)cbWritten;
    627             cbChunk  -= (uint32_t)cbWritten;
    628         }
    629         else
    630         {
    631             LogRel(("OSS: Failed writing output data: %s (%d)\n", strerror(errno), errno));
    632             return RTErrConvertFromErrno(errno);
    633         }
    634     }
    635 
    636     *pcbWritten = cbToWrite;
    637     return VINF_SUCCESS;
    638 }
    639 
    640 
    641 /**
    642  * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
    643  */
    644 static DECLCALLBACK(void) drvHostOssAudioHA_Shutdown(PPDMIHOSTAUDIO pInterface)
    645 {
    646     RT_NOREF(pInterface);
    647 }
    648 
    649 
    650 /**
    651  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
    652  */
    653 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostOssAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
    654 {
    655     AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
    656     RT_NOREF(enmDir);
    657 
    658     return PDMAUDIOBACKENDSTS_RUNNING;
    659 }
    660 
    661 
    662 /**
    663  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
    664  */
    665 static DECLCALLBACK(int) drvHostOssAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    666                                                         PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    667 {
    668     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    669     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    670     AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
    671     AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
    672 
    673     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    674 
    675     int rc;
    676     if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    677         rc = ossCreateStreamIn (pStreamOSS, pCfgReq, pCfgAcq);
    678     else
    679         rc = ossCreateStreamOut(pStreamOSS, pCfgReq, pCfgAcq);
    680 
    681     if (RT_SUCCESS(rc))
    682     {
    683         pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);
    684         if (!pStreamOSS->pCfg)
    685             rc = VERR_NO_MEMORY;
    686     }
    687 
    688     return rc;
    689 }
    690 
    691 
    692 /**
    693  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
    694  */
    695 static DECLCALLBACK(int) drvHostOssAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    696 {
    697     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    698     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    699 
    700     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    701 
    702     if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */
    703         return VINF_SUCCESS;
    704 
    705     int rc;
    706     if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN)
    707         rc = ossDestroyStreamIn(pStream);
    708     else
    709         rc = ossDestroyStreamOut(pStream);
    710 
    711     if (RT_SUCCESS(rc))
    712     {
    713         PDMAudioStrmCfgFree(pStreamOSS->pCfg);
    714         pStreamOSS->pCfg = NULL;
    715     }
    716 
    717     return rc;
    718 }
    719 
    720 
    721 /**
    722  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
    723  */
    724 static DECLCALLBACK(int) drvHostOssAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    725                                                          PDMAUDIOSTREAMCMD enmStreamCmd)
    726 {
    727     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    728     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    729 
    730     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    731 
    732     if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */
    733         return VINF_SUCCESS;
    734 
    735     int rc;
    736     if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN)
    737         rc = ossControlStreamIn(/*pInterface,  pStream, enmStreamCmd*/);
    738     else
    739         rc = ossControlStreamOut(pStreamOSS, enmStreamCmd);
    740 
    741     return rc;
    742 }
    743 
    744 
    745 /**
    746  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
    747  */
    748 static DECLCALLBACK(int) drvHostOssAudioHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    749 {
    750     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    751     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    752 
    753     LogFlowFuncEnter();
    754 
    755     /* Nothing to do here for OSS. */
    756     return VINF_SUCCESS;
    757 }
    758 
    759 
    760 /**
    761  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
    762  */
    763 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    764 {
    765     RT_NOREF(pInterface, pStream);
    766     return UINT32_MAX;
    767 }
    768 
    769 
    770 /**
    771  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
    772  */
    773 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    774 {
    775     POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    776     AssertPtr(pStreamOSS);
    777     RT_NOREF(pInterface);
    778 
    779     /*
    780      * Note! This logic was found in StreamPlay and corrected a little.
    781      *
    782      * The logic here must match what StreamPlay does.
    783      */
    784     audio_buf_info abinfo = { 0, 0, 0, 0 };
    785     int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
    786     AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0);
    787 
    788 #if 0 /** @todo we could return abinfo.bytes here iff StreamPlay didn't use the fragmented approach */
    789     /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */
    790     AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3);
    791     if ((unsigned)abinfo.bytes > cbBuf)
    792     {
    793         LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf));
    794         abinfo.bytes = cbBuf;
    795         /* Keep going. */
    796     }
    797 #endif
    798 
    799     return (uint32_t)(abinfo.fragments * abinfo.fragsize);
    800 }
    801 
    802 
    803 /**
    804  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
    805  */
    806 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostOssAudioHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    807 {
    808     RT_NOREF(pInterface, pStream);
    809     return PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED;
    810 }
    811772
    812773/**
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