VirtualBox

Ignore:
Timestamp:
Mar 25, 2021 12:11:23 PM (4 years ago)
Author:
vboxsync
Message:

DrvHostAudioOss: Reduced and refactored the stream creation code. bugref:9890

File:
1 edited

Legend:

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

    r88289 r88291  
    279279
    280280
    281 static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pOSSReq, POSSAUDIOSTREAMCFG pOSSAcq, int *phFile)
    282 {
    283     int rc = VINF_SUCCESS;
    284 
    285     int fdFile = -1;
    286     do
    287     {
    288         fdFile = open(pszDev, fOpen);
    289         if (fdFile == -1)
    290         {
    291             LogRel(("OSS: Failed to open %s: %s (%d)\n", pszDev, strerror(errno), errno));
    292             break;
    293         }
    294 
    295         int iFormat;
    296         switch (PDMAudioPropsSampleSize(&pOSSReq->Props))
    297         {
    298             case 1:
    299                 iFormat = pOSSReq->Props.fSigned ? AFMT_S8 : AFMT_U8;
    300                 break;
    301 
    302             case 2:
    303                 if (PDMAudioPropsIsLittleEndian(&pOSSReq->Props))
    304                     iFormat = pOSSReq->Props.fSigned ? AFMT_S16_LE : AFMT_U16_LE;
    305                 else
    306                     iFormat = pOSSReq->Props.fSigned ? AFMT_S16_BE : AFMT_U16_BE;
    307                 break;
    308 
    309             default:
    310                 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    311                 break;
    312         }
    313 
    314         if (RT_FAILURE(rc))
    315             break;
    316 
    317         if (ioctl(fdFile, SNDCTL_DSP_SAMPLESIZE, &iFormat))
    318         {
    319             LogRel(("OSS: Failed to set audio format to %ld: %s (%d)\n", iFormat, strerror(errno), errno));
    320             break;
    321         }
    322 
    323         int cChannels = PDMAudioPropsChannels(&pOSSReq->Props);
    324         if (ioctl(fdFile, SNDCTL_DSP_CHANNELS, &cChannels))
    325         {
    326             LogRel(("OSS: Failed to set number of audio channels (%RU8): %s (%d)\n",
    327                     PDMAudioPropsChannels(&pOSSReq->Props), strerror(errno), errno));
    328             break;
    329         }
    330 
    331         int freq = pOSSReq->Props.uHz;
    332         if (ioctl(fdFile, SNDCTL_DSP_SPEED, &freq))
    333         {
    334             LogRel(("OSS: Failed to set audio frequency (%dHZ): %s (%d)\n", pOSSReq->Props.uHz, strerror(errno), errno));
    335             break;
    336         }
    337 
    338         /* Obsolete on Solaris (using O_NONBLOCK is sufficient). */
    339 #if !(defined(VBOX) && defined(RT_OS_SOLARIS))
    340         if (ioctl(fdFile, SNDCTL_DSP_NONBLOCK))
    341         {
    342             LogRel(("OSS: Failed to set non-blocking mode: %s (%d)\n", strerror(errno), errno));
    343             break;
    344         }
     281static int ossStreamConfigure(int hFile, bool fInput, POSSAUDIOSTREAMCFG pOSSReq, POSSAUDIOSTREAMCFG pOSSAcq)
     282{
     283    /*
     284     * Format.
     285     */
     286    int iFormat;
     287    switch (PDMAudioPropsSampleSize(&pOSSReq->Props))
     288    {
     289        case 1:
     290            iFormat = pOSSReq->Props.fSigned ? AFMT_S8 : AFMT_U8;
     291            break;
     292
     293        case 2:
     294            if (PDMAudioPropsIsLittleEndian(&pOSSReq->Props))
     295                iFormat = pOSSReq->Props.fSigned ? AFMT_S16_LE : AFMT_U16_LE;
     296            else
     297                iFormat = pOSSReq->Props.fSigned ? AFMT_S16_BE : AFMT_U16_BE;
     298            break;
     299
     300        default:
     301            LogRel2(("OSS: Unsupported sample size: %u\n", PDMAudioPropsSampleSize(&pOSSReq->Props)));
     302            return VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     303    }
     304    AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_SAMPLESIZE, &iFormat) >= 0,
     305                          ("OSS: Failed to set audio format to %d: %s (%d)\n", iFormat, strerror(errno), errno),
     306                          RTErrConvertFromErrno(errno));
     307
     308    /*
     309     * Channel count.
     310     */
     311    int cChannels = PDMAudioPropsChannels(&pOSSReq->Props);
     312    AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_CHANNELS, &cChannels) >= 0,
     313                          ("OSS: Failed to set number of audio channels (%RU8): %s (%d)\n",
     314                           PDMAudioPropsChannels(&pOSSReq->Props), strerror(errno), errno),
     315                          RTErrConvertFromErrno(errno));
     316
     317    /*
     318     * Frequency.
     319     */
     320    int iFrequenc = pOSSReq->Props.uHz;
     321    AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_SPEED, &iFrequenc) >= 0,
     322                          ("OSS: Failed to set audio frequency to %d Hz: %s (%d)\n", pOSSReq->Props.uHz, strerror(errno), errno),
     323                          RTErrConvertFromErrno(errno));
     324
     325
     326    /*
     327     * Set obsolete non-blocking call for input streams.
     328     */
     329    if (fInput)
     330    {
     331#if !(defined(VBOX) && defined(RT_OS_SOLARIS)) /* Obsolete on Solaris (using O_NONBLOCK is sufficient). */
     332        AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_NONBLOCK, NULL) >= 0,
     333                              ("OSS: Failed to set non-blocking mode: %s (%d)\n", strerror(errno), errno),
     334                              RTErrConvertFromErrno(errno));
    345335#endif
    346 
    347         /* Check access mode (input or output). */
    348         bool fIn = ((fOpen & O_ACCMODE) == O_RDONLY);
    349 
    350         LogRel2(("OSS: Requested %RU16 %s fragments, %RU32 bytes each\n",
    351                  pOSSReq->cFragments, fIn ? "input" : "output", pOSSReq->cbFragmentSize));
    352 
    353         int mmmmssss = (pOSSReq->cFragments << 16) | lsbindex(pOSSReq->cbFragmentSize);
    354         if (ioctl(fdFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss))
    355         {
    356             LogRel(("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s (%d)\n",
    357                     pOSSReq->cFragments, pOSSReq->cbFragmentSize, strerror(errno), errno));
    358             break;
    359         }
    360 
    361         audio_buf_info abinfo;
    362         if (ioctl(fdFile, fIn ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo))
    363         {
    364             LogRel(("OSS: Failed to retrieve %c"
    365                     "s buffer length: %s (%d)\n", fIn ? "input" : "output", strerror(errno), errno));
    366             break;
    367         }
    368 
    369         rc = ossOSSToAudioProps(&pOSSAcq->Props, iFormat, cChannels, freq);
    370         if (RT_SUCCESS(rc))
    371         {
    372             pOSSAcq->cFragments      = abinfo.fragstotal;
    373             pOSSAcq->cbFragmentSize  = abinfo.fragsize;
    374 
    375             LogRel2(("OSS: Got %RU16 %s fragments, %RU32 bytes each\n",
    376                      pOSSAcq->cFragments, fIn ? "input" : "output", pOSSAcq->cbFragmentSize));
    377 
    378             *phFile = fdFile;
    379         }
    380     }
    381     while (0);
    382 
    383     if (RT_FAILURE(rc))
    384         ossStreamClose(&fdFile);
    385 
    386     LogFlowFuncLeaveRC(rc);
    387     return rc;
    388 }
    389 
    390 
    391 static 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 
    439 static 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);
     336    }
     337
     338    /*
     339     * Set fragment size and count.
     340     */
     341    LogRel2(("OSS: Requested %RU16 %s fragments, %RU32 bytes each\n",
     342             pOSSReq->cFragments, fInput ? "input" : "output", pOSSReq->cbFragmentSize));
     343
     344    int mmmmssss = (pOSSReq->cFragments << 16) | lsbindex(pOSSReq->cbFragmentSize);
     345    AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss) >= 0,
     346                          ("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s (%d)\n",
     347                           pOSSReq->cFragments, pOSSReq->cbFragmentSize, strerror(errno), errno),
     348                          RTErrConvertFromErrno(errno));
     349
     350    /*
     351     * Get parameters and popuplate pOSSAcq.
     352     */
     353    audio_buf_info BufInfo = { 0, 0, 0, 0 };
     354    AssertLogRelMsgReturn(ioctl(hFile, fInput ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &BufInfo) >= 0,
     355                          ("OSS: Failed to retrieve %s buffer length: %s (%d)\n",
     356                           fInput ? "input" : "output", strerror(errno), errno),
     357                          RTErrConvertFromErrno(errno));
     358
     359    int rc = ossOSSToAudioProps(&pOSSAcq->Props, iFormat, cChannels, iFrequenc);
    453360    if (RT_SUCCESS(rc))
    454361    {
    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);
     362        pOSSAcq->cFragments      = BufInfo.fragstotal;
     363        pOSSAcq->cbFragmentSize  = BufInfo.fragsize;
     364
     365        LogRel2(("OSS: Got %RU16 %s fragments, %RU32 bytes each\n",
     366                 pOSSAcq->cFragments, fInput ? "input" : "output", pOSSAcq->cbFragmentSize));
     367    }
     368
    469369    return rc;
    470370}
     
    477377                                                        PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    478378{
    479     AssertPtr(pInterface);
     379    AssertPtr(pInterface); RT_NOREF(pInterface);
    480380    POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;
    481381    AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);
     
    483383    AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
    484384
    485     pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);
    486     AssertReturn(pStreamOSS->pCfg, VERR_NO_MEMORY);
    487 
     385    /*
     386     * Open the device
     387     */
    488388    int rc;
    489389    if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    490         rc = ossCreateStreamIn( pStreamOSS, pCfgReq, pCfgAcq);
     390        pStreamOSS->hFile = open(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK);
    491391    else
    492         rc = ossCreateStreamOut(pStreamOSS, pCfgReq, pCfgAcq);
    493 
    494     if (RT_FAILURE(rc))
    495     {
    496         PDMAudioStrmCfgFree(pStreamOSS->pCfg);
    497         pStreamOSS->pCfg = NULL;
     392        pStreamOSS->hFile = open(s_OSSConf.devpath_out, O_WRONLY);
     393    if (pStreamOSS->hFile >= 0)
     394    {
     395        /*
     396         * Configure it.
     397         */
     398        OSSAUDIOSTREAMCFG ReqOssCfg;
     399        RT_ZERO(ReqOssCfg);
     400
     401        memcpy(&ReqOssCfg.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));
     402        ReqOssCfg.cFragments     = s_OSSConf.nfrags;
     403        ReqOssCfg.cbFragmentSize = s_OSSConf.fragsize;
     404
     405        OSSAUDIOSTREAMCFG AcqOssCfg;
     406        RT_ZERO(AcqOssCfg);
     407        rc = ossStreamConfigure(pStreamOSS->hFile, pCfgReq->enmDir == PDMAUDIODIR_IN, &ReqOssCfg, &AcqOssCfg);
     408        if (RT_SUCCESS(rc))
     409        {
     410            /*
     411             * Complete the stream structure and fill in the pCfgAcq bits.
     412             */
     413            if ((AcqOssCfg.cFragments * AcqOssCfg.cbFragmentSize) & pStreamOSS->uAlign)
     414                LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n",
     415                        AcqOssCfg.cFragments * AcqOssCfg.cbFragmentSize, pStreamOSS->uAlign + 1));
     416
     417            memcpy(&pCfgAcq->Props, &AcqOssCfg.Props, sizeof(PDMAUDIOPCMPROPS));
     418            pCfgAcq->Backend.cFramesPeriod     = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, AcqOssCfg.cbFragmentSize);
     419            pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */
     420            /** @todo Pre-buffering required? */
     421
     422            /*
     423             * Duplicate the stream config and we're done!
     424             */
     425            pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);
     426            if (pStreamOSS->pCfg)
     427                return VINF_SUCCESS;
     428
     429            rc = VERR_NO_MEMORY;
     430        }
     431        ossStreamClose(&pStreamOSS->hFile);
     432    }
     433    else
     434    {
     435        rc = RTErrConvertFromErrno(errno);
     436        LogRel(("OSS: Failed to open '%s': %s (%d) / %Rrc\n",
     437                pCfgReq->enmDir == PDMAUDIODIR_IN ? s_OSSConf.devpath_in : s_OSSConf.devpath_out, strerror(errno), errno, rc));
    498438    }
    499439    return rc;
     
    617557     * The logic here must match what StreamPlay does.
    618558     */
    619     audio_buf_info abinfo = { 0, 0, 0, 0 };
    620     int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
     559    audio_buf_info BufInfo = { 0, 0, 0, 0 };
     560    int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &BufInfo);
    621561    AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0);
    622562
    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;
     563#if 0 /** @todo we could return BufInfo.bytes here iff StreamPlay didn't use the fragmented approach */
     564    /** @todo r=bird: WTF do we make a fuss over BufInfo.bytes for when we don't
     565     *        even use it?!? */
     566    AssertLogRelMsgReturn(BufInfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", BufInfo.bytes), VERR_INTERNAL_ERROR_3);
     567    if ((unsigned)BufInfo.bytes > cbBuf)
     568    {
     569        LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", BufInfo.bytes, cbBuf, cbBuf));
     570        BufInfo.bytes = cbBuf;
    630571        /* Keep going. */
    631572    }
    632573#endif
    633574
    634     return (uint32_t)(abinfo.fragments * abinfo.fragsize);
     575    return (uint32_t)(BufInfo.fragments * BufInfo.fragsize);
    635576}
    636577
     
    675616     */
    676617    uint32_t cbToWrite;
    677     audio_buf_info abinfo;
    678     int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
     618    audio_buf_info BufInfo;
     619    int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &BufInfo);
    679620    AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno),
    680621                          RTErrConvertFromErrno(errno));
    681622
    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;
     623#if 0   /** @todo r=bird: WTF do we make a fuss over BufInfo.bytes for when we don't even use it?!? */
     624    AssertLogRelMsgReturn(BufInfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", BufInfo.bytes), VERR_INTERNAL_ERROR_3);
     625    if ((unsigned)BufInfo.bytes > cbBuf)
     626    {
     627        LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", BufInfo.bytes, cbBuf, cbBuf));
     628        BufInfo.bytes = cbBuf;
    688629        /* Keep going. */
    689630    }
    690631#endif
    691     cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize);
     632    cbToWrite = (unsigned)(BufInfo.fragments * BufInfo.fragsize);
    692633    cbToWrite = RT_MIN(cbToWrite, cbBuf);
    693634
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