Changeset 89516 in vbox for trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
- Timestamp:
- Jun 4, 2021 10:27:55 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
r89510 r89516 20 20 * Header Files * 21 21 *********************************************************************************************************************************/ 22 #define LOG_ENABLED 1 22 23 #include <errno.h> 23 24 #include <fcntl.h> … … 298 299 RTErrConvertFromErrno(errno)); 299 300 300 301 /*302 * Set obsolete non-blocking call for input streams.303 */304 if (fInput)305 {306 #if !(defined(VBOX) && defined(RT_OS_SOLARIS)) /* Obsolete on Solaris (using O_NONBLOCK is sufficient). */307 AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_NONBLOCK, NULL) >= 0,308 ("OSS: Failed to set non-blocking mode: %s (%d)\n", strerror(errno), errno),309 RTErrConvertFromErrno(errno));310 #endif311 }312 313 301 /* 314 302 * Set fragment size and count. … … 367 355 int rc; 368 356 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 369 pStreamOSS->hFile = open(g_szPathInputDev, O_RDONLY | O_NONBLOCK);357 pStreamOSS->hFile = open(g_szPathInputDev, O_RDONLY); 370 358 else 371 359 pStreamOSS->hFile = open(g_szPathOutputDev, O_WRONLY); … … 463 451 RT_NOREF(pInterface); 464 452 PDRVHSTAUDOSSSTREAM pStreamOSS = (PDRVHSTAUDOSSSTREAM)pStream; 465 466 /** @todo this might be a little optimisitic... */467 pStreamOSS->fDraining = false;468 469 453 int rc; 470 if (pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN) 471 rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */ 454 455 /* 456 * This is most probably untested... 457 */ 458 if (pStreamOSS->fDraining) 459 { 460 LogFlowFunc(("Still draining...\n")); 461 rc = RTThreadWait(pStreamOSS->hThreadDrain, 0 /*ms*/, NULL); 462 if (RT_FAILURE(rc)) 463 { 464 LogFlowFunc(("Resetting...\n")); 465 ioctl(pStreamOSS->hFile, SNDCTL_DSP_RESET, NULL); 466 rc = RTThreadWait(pStreamOSS->hThreadDrain, 0 /*ms*/, NULL); 467 if (RT_FAILURE(rc)) 468 { 469 LogFlowFunc(("Poking...\n")); 470 RTThreadPoke(pStreamOSS->hThreadDrain); 471 rc = RTThreadWait(pStreamOSS->hThreadDrain, 1 /*ms*/, NULL); 472 } 473 } 474 if (RT_SUCCESS(rc)) 475 { 476 LogFlowFunc(("Done draining.\n")); 477 pStreamOSS->hThreadDrain = NIL_RTTHREAD; 478 } 479 else 480 LogFlowFunc(("No, still draining...\n")); 481 pStreamOSS->fDraining = false; 482 } 483 484 /* 485 * Enable the stream. 486 */ 487 int fMask = pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN ? PCM_ENABLE_INPUT : PCM_ENABLE_OUTPUT; 488 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0) 489 rc = VINF_SUCCESS; 472 490 else 473 491 { 474 int fMask = PCM_ENABLE_OUTPUT; 475 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0) 476 rc = VINF_SUCCESS; 477 else 478 { 479 LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno)); 480 rc = RTErrConvertFromErrno(errno); 481 } 492 LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno)); 493 rc = RTErrConvertFromErrno(errno); 482 494 } 483 495 … … 494 506 RT_NOREF(pInterface); 495 507 PDRVHSTAUDOSSSTREAM pStreamOSS = (PDRVHSTAUDOSSSTREAM)pStream; 496 508 LogFlowFunc(("Stream '%s'\n", pStreamOSS->Cfg.szName)); 497 509 int rc; 498 if (pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN) 499 rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */ 510 511 /* 512 * If we're still draining, try kick the thread before we try disable the stream. 513 */ 514 if (pStreamOSS->fDraining) 515 { 516 LogFlowFunc(("Trying to cancel draining...\n")); 517 if (pStreamOSS->hThreadDrain != NIL_RTTHREAD) 518 { 519 RTThreadPoke(pStreamOSS->hThreadDrain); 520 rc = RTThreadWait(pStreamOSS->hThreadDrain, 1 /*ms*/, NULL); 521 if (RT_SUCCESS(rc) || rc == VERR_INVALID_HANDLE) 522 pStreamOSS->fDraining = false; 523 else 524 LogFunc(("Failed to cancel draining (%Rrc)\n", rc)); 525 } 526 else 527 { 528 LogFlowFunc(("Thread handle is NIL, so we can't be draining\n")); 529 pStreamOSS->fDraining = false; 530 } 531 } 532 533 /* 534 * The Official documentation says this isn't the right way to stop 535 * playback. It may work in some implementations but fail in all others... 536 * Suggest SNDCTL_DSP_RESET / SNDCTL_DSP_HALT. 537 * 538 * So, let's do both and see how that works out... 539 */ 540 rc = VINF_SUCCESS; 541 int fMask = 0; 542 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0) 543 LogFlowFunc(("SNDCTL_DSP_SETTRIGGER succeeded\n")); 500 544 else 501 545 { 502 /* 503 * If we're still draining, try kick the thread before we try disable the stream. 504 */ 505 if (pStreamOSS->fDraining) 506 { 507 LogFlowFunc(("Trying to cancel draining...\n")); 508 if (pStreamOSS->hThreadDrain != NIL_RTTHREAD) 509 { 510 RTThreadPoke(pStreamOSS->hThreadDrain); 511 rc = RTThreadWait(pStreamOSS->hThreadDrain, 1 /*ms*/, NULL); 512 if (RT_SUCCESS(rc) || rc == VERR_INVALID_HANDLE) 513 pStreamOSS->fDraining = false; 514 else 515 LogFunc(("Failed to cancel draining (%Rrc)\n", rc)); 516 } 517 else 518 { 519 LogFlowFunc(("Thread handle is NIL, so we can't be draining\n")); 520 pStreamOSS->fDraining = false; 521 } 522 } 523 524 /** @todo Official documentation says this isn't the right way to stop playback. 525 * It may work in some implementations but fail in all others... Suggest 526 * using SNDCTL_DSP_RESET / SNDCTL_DSP_HALT. */ 527 int fMask = 0; 528 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0) 529 rc = VINF_SUCCESS; 530 else 531 { 532 LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno)); 533 rc = RTErrConvertFromErrno(errno); 534 } 535 } 546 LogRel(("OSS: Failed to clear triggers for stream '%s': %s (%d)\n", pStreamOSS->Cfg.szName, strerror(errno), errno)); 547 rc = RTErrConvertFromErrno(errno); 548 } 549 550 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_RESET, NULL) >= 0) 551 LogFlowFunc(("SNDCTL_DSP_RESET succeeded\n")); 552 else 553 { 554 LogRel(("OSS: Failed to reset stream '%s': %s (%d)\n", pStreamOSS->Cfg.szName, strerror(errno), errno)); 555 rc = RTErrConvertFromErrno(errno); 556 } 557 536 558 LogFlowFunc(("returns %Rrc for '%s'\n", rc, pStreamOSS->Cfg.szName)); 537 559 return rc; … … 571 593 LogFunc(("F_GETFL -> %#x\n", fOrgFlags)); 572 594 Assert(fOrgFlags != -1); 573 if (fOrgFlags != -1 )595 if (fOrgFlags != -1 && (fOrgFlags & O_NONBLOCK)) 574 596 { 575 597 rc = fcntl(pStreamOSS->hFile, F_SETFL, fOrgFlags & ~O_NONBLOCK); … … 782 804 static DECLCALLBACK(uint32_t) drvHstAudOssHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 783 805 { 784 RT_NOREF(pInterface, pStream); 785 Log4Func(("returns UINT32_MAX\n")); 786 return UINT32_MAX; 806 RT_NOREF(pInterface); 807 PDRVHSTAUDOSSSTREAM pStreamOSS = (PDRVHSTAUDOSSSTREAM)pStream; 808 AssertPtr(pStreamOSS); 809 810 /* 811 * Use SNDCTL_DSP_GETISPACE to see how much we can read. 812 * 813 * Note! We use bytes rather than the fragments * fragsize, as these are 814 * documented as obsolete. (Playback code should do the same.) 815 */ 816 audio_buf_info BufInfo = { 0, 0, 0, 0 }; 817 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETISPACE, &BufInfo); 818 AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETISPACE failed: %s (%d)\n", strerror(errno), errno), 0); 819 820 uint32_t cbRet; 821 uint32_t const cbBuf = pStreamOSS->OssCfg.cbFragment * pStreamOSS->OssCfg.cFragments; 822 if (BufInfo.bytes >= 0 && (unsigned)BufInfo.bytes <= cbBuf) 823 cbRet = BufInfo.bytes; 824 else 825 { 826 AssertMsgFailed(("Invalid available size: %d\n", BufInfo.bytes)); 827 AssertMsgReturn(BufInfo.fragments >= 0, ("fragments: %d\n", BufInfo.fragments), 0); 828 AssertMsgReturn(BufInfo.fragsize >= 0, ("fragsize: %d\n", BufInfo.fragsize), 0); 829 cbRet = (uint32_t)(BufInfo.fragments * BufInfo.fragsize); 830 AssertMsgStmt(cbRet <= cbBuf, ("fragsize*fragments: %d, cbBuf=%#x\n", cbRet, cbBuf), 0); 831 } 832 833 /* 834 * HACK ALERT! Tweak to force recording to start. Pretend there are bytes 835 * available if we haven't read anything yet. This will cause 836 * the following StreamCapture call to block and make sure the 837 * stream is really recording. 838 */ 839 if (BufInfo.bytes > 0 || pStreamOSS->offInternal != 0) 840 { /* likely */ } 841 else 842 cbRet = PDMAudioPropsFramesToBytes(&pStreamOSS->Cfg.Props, 1); 843 844 Log4Func(("returns %#x (%u) [cbBuf=%#x)\n", cbRet, cbRet, cbBuf)); 845 return cbRet; 787 846 } 788 847 … … 805 864 { 806 865 ssize_t cbRead = read(pStreamOSS->hFile, &pbDst[offWrite], cbToRead); 807 if (cbRead )866 if (cbRead > 0) 808 867 { 809 868 LogFlowFunc(("cbRead=%zi, offWrite=%zu cbToRead=%zu\n", cbRead, offWrite, cbToRead));
Note:
See TracChangeset
for help on using the changeset viewer.