Changeset 88291 in vbox for trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
- Timestamp:
- Mar 25, 2021 12:11:23 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
r88289 r88291 279 279 280 280 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 } 281 static 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)); 345 335 #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); 453 360 if (RT_SUCCESS(rc)) 454 361 { 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 469 369 return rc; 470 370 } … … 477 377 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 478 378 { 479 AssertPtr(pInterface); 379 AssertPtr(pInterface); RT_NOREF(pInterface); 480 380 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 481 381 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); … … 483 383 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 484 384 485 pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);486 AssertReturn(pStreamOSS->pCfg, VERR_NO_MEMORY);487 385 /* 386 * Open the device 387 */ 488 388 int rc; 489 389 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 490 rc = ossCreateStreamIn( pStreamOSS, pCfgReq, pCfgAcq);390 pStreamOSS->hFile = open(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK); 491 391 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)); 498 438 } 499 439 return rc; … … 617 557 * The logic here must match what StreamPlay does. 618 558 */ 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); 621 561 AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0); 622 562 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; 630 571 /* Keep going. */ 631 572 } 632 573 #endif 633 574 634 return (uint32_t)( abinfo.fragments * abinfo.fragsize);575 return (uint32_t)(BufInfo.fragments * BufInfo.fragsize); 635 576 } 636 577 … … 675 616 */ 676 617 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); 679 620 AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno), 680 621 RTErrConvertFromErrno(errno)); 681 622 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; 688 629 /* Keep going. */ 689 630 } 690 631 #endif 691 cbToWrite = (unsigned)( abinfo.fragments * abinfo.fragsize);632 cbToWrite = (unsigned)(BufInfo.fragments * BufInfo.fragsize); 692 633 cbToWrite = RT_MIN(cbToWrite, cbBuf); 693 634
Note:
See TracChangeset
for help on using the changeset viewer.