Changeset 88288 in vbox
- Timestamp:
- Mar 25, 2021 11:00:38 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
r88287 r88288 83 83 /** Buffer alignment. */ 84 84 uint8_t uAlign; 85 union86 {87 struct88 {89 90 } In;91 struct92 {93 #ifndef RT_OS_L494 /** Whether we use a memory mapped file instead of our95 * own allocated PCM buffer below. */96 /** @todo The memory mapped code seems to be utterly broken.97 * Needs investigation! */98 bool fMMIO;99 #endif100 } Out;101 };102 85 int hFile; 103 86 int cFragments; 104 87 int cbFragmentSize; 105 /** Own PCM buffer. */106 void *pvBuf;107 /** Size (in bytes) of own PCM buffer. */108 size_t cbBuf;109 88 int old_optr; 110 89 } OSSAUDIOSTREAM, *POSSAUDIOSTREAM; … … 112 91 typedef struct OSSAUDIOCFG 113 92 { 114 #ifndef RT_OS_L4115 bool try_mmap;116 #endif117 93 int nfrags; 118 94 int fragsize; … … 124 100 static OSSAUDIOCFG s_OSSConf = 125 101 { 126 #ifndef RT_OS_L4127 false,128 #endif129 102 4, 130 103 4096, … … 339 312 case PDMAUDIOSTREAMCMD_RESUME: 340 313 { 341 PDMAudioPropsClearBuffer(&pStreamOSS->pCfg->Props, pStreamOSS->pvBuf, pStreamOSS->cbBuf,342 PDMAUDIOPCMPROPS_B2F(&pStreamOSS->pCfg->Props, pStreamOSS->cbBuf));343 344 314 int mask = PCM_ENABLE_OUTPUT; 345 315 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0) … … 391 361 void *pvBuf, uint32_t uBufSize, uint32_t *puRead) 392 362 { 363 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 364 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); 393 365 RT_NOREF(pInterface); 394 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 395 396 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 397 398 int rc = VINF_SUCCESS; 399 400 size_t cbToRead = RT_MIN(pStreamOSS->cbBuf, uBufSize); 401 366 367 368 size_t cbToRead = uBufSize; 402 369 LogFlowFunc(("cbToRead=%zi\n", cbToRead)); 403 370 404 uint32_t cbReadTotal = 0; 405 uint32_t cbTemp; 406 ssize_t cbRead; 407 size_t offWrite = 0; 408 409 while (cbToRead) 410 { 411 cbTemp = RT_MIN(cbToRead, pStreamOSS->cbBuf); 412 AssertBreakStmt(cbTemp, rc = VERR_NO_DATA); 413 cbRead = read(pStreamOSS->hFile, (uint8_t *)pStreamOSS->pvBuf, cbTemp); 414 415 LogFlowFunc(("cbRead=%zi, cbTemp=%RU32, cbToRead=%zu\n", cbRead, cbTemp, cbToRead)); 416 417 if (cbRead < 0) 418 { 419 switch (errno) 420 { 421 case 0: 422 { 423 LogFunc(("Failed to read %z frames\n", cbRead)); 424 rc = VERR_ACCESS_DENIED; 425 break; 426 } 427 428 case EINTR: 429 case EAGAIN: 430 rc = VERR_NO_DATA; 431 break; 432 433 default: 434 LogFlowFunc(("Failed to read %zu input frames, rc=%Rrc\n", cbTemp, rc)); 435 rc = VERR_GENERAL_FAILURE; /** @todo Fix this. */ 436 break; 437 } 438 439 if (RT_FAILURE(rc)) 440 break; 441 } 442 else if (cbRead) 443 { 444 memcpy((uint8_t *)pvBuf + offWrite, pStreamOSS->pvBuf, cbRead); 445 371 uint8_t * const pbDst = (uint8_t *)pvBuf; 372 size_t offWrite = 0; 373 while (cbToRead > 0) 374 { 375 ssize_t cbRead = read(pStreamOSS->hFile, &pbDst[offWrite], cbToRead); 376 if (cbRead) 377 { 378 LogFlowFunc(("cbRead=%zi, offWrite=%zu cbToRead=%zu\n", cbRead, offWrite, cbToRead)); 446 379 Assert((ssize_t)cbToRead >= cbRead); 447 380 cbToRead -= cbRead; 448 381 offWrite += cbRead; 449 cbReadTotal += cbRead; 450 } 451 else /* No more data, try next round. */ 452 break; 453 } 454 455 if (rc == VERR_NO_DATA) 456 rc = VINF_SUCCESS; 457 458 if (RT_SUCCESS(rc)) 459 { 460 if (puRead) 461 *puRead = cbReadTotal; 462 } 463 464 return rc; 382 } 383 else 384 { 385 LogFunc(("cbRead=%zi, offWrite=%zu cbToRead=%zu errno=%d\n", cbRead, offWrite, cbToRead, errno)); 386 387 /* Don't complain about errors if we've retrieved some audio data already. */ 388 if (cbRead < 0 && offWrite == 0 && errno != EINTR && errno != EAGAIN) 389 { 390 AssertStmt(errno != 0, errno = EACCES); 391 int rc = RTErrConvertFromErrno(errno); 392 LogFunc(("Failed to read %zu input frames, errno=%d rc=%Rrc\n", cbToRead, errno, rc)); 393 return rc; 394 } 395 break; 396 } 397 } 398 399 if (puRead) 400 *puRead = offWrite; 401 return VINF_SUCCESS; 465 402 } 466 403 … … 472 409 LogFlowFuncEnter(); 473 410 474 if (pStreamOSS->pvBuf)475 {476 Assert(pStreamOSS->cbBuf);477 478 RTMemFree(pStreamOSS->pvBuf);479 pStreamOSS->pvBuf = NULL;480 }481 482 pStreamOSS->cbBuf = 0;483 484 411 ossStreamClose(&pStreamOSS->hFile); 485 412 … … 491 418 { 492 419 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 493 494 #ifndef RT_OS_L4495 if (pStreamOSS->Out.fMMIO)496 {497 if (pStreamOSS->pvBuf)498 {499 Assert(pStreamOSS->cbBuf);500 501 int rc2 = munmap(pStreamOSS->pvBuf, pStreamOSS->cbBuf);502 if (rc2 == 0)503 {504 pStreamOSS->pvBuf = NULL;505 pStreamOSS->cbBuf = 0;506 507 pStreamOSS->Out.fMMIO = false;508 }509 else510 LogRel(("OSS: Failed to memory unmap playback buffer on close: %s\n", strerror(errno)));511 }512 }513 else514 #endif515 {516 if (pStreamOSS->pvBuf)517 {518 Assert(pStreamOSS->cbBuf);519 520 RTMemFree(pStreamOSS->pvBuf);521 pStreamOSS->pvBuf = NULL;522 }523 524 pStreamOSS->cbBuf = 0;525 }526 420 527 421 ossStreamClose(&pStreamOSS->hFile); … … 632 526 if (RT_SUCCESS(rc)) 633 527 { 634 size_t cbBuf = PDMAUDIOSTREAMCFG_F2B(pCfgAcq, ossAcq.cFragments * ossAcq.cbFragmentSize);635 void *pvBuf = RTMemAlloc(cbBuf);636 if (!pvBuf)637 {638 LogRel(("OSS: Failed allocating capturing buffer with (%zu bytes)\n", cbBuf));639 rc = VERR_NO_MEMORY;640 }641 642 528 pStreamOSS->hFile = hFile; 643 pStreamOSS->pvBuf = pvBuf;644 pStreamOSS->cbBuf = cbBuf;645 529 646 530 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, ossAcq.cbFragmentSize); … … 662 546 static int ossCreateStreamOut(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 663 547 { 664 int rc; 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 665 558 int hFile = -1; 666 667 do 668 { 669 OSSAUDIOSTREAMCFG reqStream; 670 RT_ZERO(reqStream); 671 672 OSSAUDIOSTREAMCFG obtStream; 673 RT_ZERO(obtStream); 674 675 memcpy(&reqStream.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS)); 676 677 reqStream.cFragments = s_OSSConf.nfrags; 678 reqStream.cbFragmentSize = s_OSSConf.fragsize; 679 680 rc = ossStreamOpen(s_OSSConf.devpath_out, O_WRONLY, &reqStream, &obtStream, &hFile); 681 if (RT_SUCCESS(rc)) 682 { 683 memcpy(&pCfgAcq->Props, &obtStream.Props, sizeof(PDMAUDIOPCMPROPS)); 684 685 if (obtStream.cFragments * obtStream.cbFragmentSize & pStreamOSS->uAlign) 686 { 687 LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n", 688 obtStream.cFragments * obtStream.cbFragmentSize, pStreamOSS->uAlign + 1)); 689 } 690 } 691 692 if (RT_SUCCESS(rc)) /** @todo r=bird: great code structure ... */ 693 { 694 pStreamOSS->Out.fMMIO = false; 695 696 size_t cbBuf = PDMAUDIOSTREAMCFG_F2B(pCfgAcq, obtStream.cFragments * obtStream.cbFragmentSize); 697 Assert(cbBuf); 698 699 #ifndef RT_OS_L4 700 if (s_OSSConf.try_mmap) 701 { 702 pStreamOSS->pvBuf = mmap(0, cbBuf, PROT_READ | PROT_WRITE, MAP_SHARED, hFile, 0); 703 if (pStreamOSS->pvBuf == MAP_FAILED) 704 { 705 LogRel(("OSS: Failed to memory map %zu bytes of playback buffer: %s\n", cbBuf, strerror(errno))); 706 rc = RTErrConvertFromErrno(errno); 707 break; 708 } 709 else 710 { 711 int mask = 0; 712 if (ioctl(hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0) 713 { 714 LogRel(("OSS: Failed to retrieve initial trigger mask for playback buffer: %s\n", strerror(errno))); 715 rc = RTErrConvertFromErrno(errno); 716 /* Note: No break here, need to unmap file first! */ 717 } 718 else 719 { 720 mask = PCM_ENABLE_OUTPUT; 721 if (ioctl (hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0) 722 { 723 LogRel(("OSS: Failed to retrieve PCM_ENABLE_OUTPUT mask: %s\n", strerror(errno))); 724 rc = RTErrConvertFromErrno(errno); 725 /* Note: No break here, need to unmap file first! */ 726 } 727 else 728 { 729 pStreamOSS->Out.fMMIO = true; 730 LogRel(("OSS: Using MMIO\n")); 731 } 732 } 733 734 if (RT_FAILURE(rc)) 735 { 736 int rc2 = munmap(pStreamOSS->pvBuf, cbBuf); 737 if (rc2) 738 LogRel(("OSS: Failed to memory unmap playback buffer: %s\n", strerror(errno))); 739 break; 740 } 741 } 742 } 743 #endif /* !RT_OS_L4 */ 744 745 /* Memory mapping failed above? Try allocating an own buffer. */ 746 #ifndef RT_OS_L4 747 if (!pStreamOSS->Out.fMMIO) 748 { 749 #endif 750 void *pvBuf = RTMemAlloc(cbBuf); 751 if (!pvBuf) 752 { 753 LogRel(("OSS: Failed allocating playback buffer with %zu bytes\n", cbBuf)); 754 rc = VERR_NO_MEMORY; 755 break; 756 } 757 758 pStreamOSS->hFile = hFile; 759 pStreamOSS->pvBuf = pvBuf; 760 pStreamOSS->cbBuf = cbBuf; 761 #ifndef RT_OS_L4 762 } 763 #endif 764 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, obtStream.cbFragmentSize); 765 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */ 766 } 767 768 } while (0); 769 770 if (RT_FAILURE(rc)) 771 ossStreamClose(&hFile); 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 } 772 574 773 575 LogFlowFuncLeaveRC(rc); … … 790 592 */ 791 593 uint32_t cbToWrite; 792 #ifndef RT_OS_L4 793 count_info CountInfo = {0,0,0}; 794 if (pStreamOSS->Out.fMMIO) 795 { 796 /* Get current playback pointer. */ 797 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOPTR, &CountInfo); 798 AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback pointer: %s (%d)\n", strerror(errno), errno), 799 RTErrConvertFromErrno(errno)); 800 801 int cbData; 802 if (CountInfo.ptr >= pStreamOSS->old_optr) 803 cbData = CountInfo.ptr - pStreamOSS->old_optr; 804 else 805 cbData = pStreamOSS->cbBuf + CountInfo.ptr - pStreamOSS->old_optr; 806 Assert(cbData >= 0); 807 cbToWrite = (unsigned)cbData; 808 } 809 else 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 } 810 607 #endif 811 { 812 audio_buf_info abinfo; 813 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo); 814 AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno), 815 RTErrConvertFromErrno(errno)); 816 817 #if 0 /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */ 818 AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3); 819 if ((unsigned)abinfo.bytes > cbBuf) 820 { 821 LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf)); 822 abinfo.bytes = cbBuf; 823 /* Keep going. */ 824 } 825 #endif 826 cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize); 827 } 608 cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize); 828 609 cbToWrite = RT_MIN(cbToWrite, cbBuf); 829 cbToWrite = RT_MIN(cbToWrite, pStreamOSS->cbBuf);830 831 /*832 * This is probably for the mmap functionality and not needed in the no-mmap case.833 */834 /** @todo skip for non-mmap? */835 uint8_t *pbBuf = (uint8_t *)memcpy(pStreamOSS->pvBuf, pvBuf, cbToWrite);836 610 837 611 /* 838 612 * Write. 839 613 */ 840 uint32_t cbChunk = cbToWrite; 841 uint32_t offChunk = 0; 614 uint8_t const *pbBuf = (uint8_t const *)pvBuf; 615 uint32_t cbChunk = cbToWrite; 616 uint32_t offChunk = 0; 842 617 while (cbChunk > 0) 843 618 { … … 858 633 } 859 634 } 860 861 #ifndef RT_OS_L4862 /* Update read pointer. */863 if (pStreamOSS->Out.fMMIO)864 pStreamOSS->old_optr = CountInfo.ptr;865 #endif866 635 867 636 *pcbWritten = cbToWrite; … … 1013 782 * The logic here must match what StreamPlay does. 1014 783 */ 1015 uint32_t cbWritable; 1016 #ifndef RT_OS_L4 1017 count_info CountInfo = {0,0,0}; 1018 if (pStreamOSS->Out.fMMIO) 1019 { 1020 /* Get current playback pointer. */ 1021 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOPTR, &CountInfo); 1022 AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOPTR failed: %s (%d)\n", strerror(errno), errno), 0); 1023 1024 int cbData; 1025 if (CountInfo.ptr >= pStreamOSS->old_optr) 1026 cbData = CountInfo.ptr - pStreamOSS->old_optr; 1027 else 1028 cbData = pStreamOSS->cbBuf + CountInfo.ptr - pStreamOSS->old_optr; 1029 Assert(cbData >= 0); 1030 cbWritable = (unsigned)cbData; 1031 } 1032 else 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 } 1033 797 #endif 1034 { 1035 audio_buf_info abinfo = { 0, 0, 0, 0 }; 1036 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo); 1037 AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0); 1038 1039 #if 0 /** @todo we could return abinfo.bytes here iff StreamPlay didn't use the fragmented approach */ 1040 /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */ 1041 AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3); 1042 if ((unsigned)abinfo.bytes > cbBuf) 1043 { 1044 LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf)); 1045 abinfo.bytes = cbBuf; 1046 /* Keep going. */ 1047 } 1048 #endif 1049 1050 cbWritable = (uint32_t)(abinfo.fragments * abinfo.fragsize); 1051 } 1052 cbWritable = RT_MIN(cbWritable, pStreamOSS->cbBuf); 1053 return cbWritable; 798 799 return (uint32_t)(abinfo.fragments * abinfo.fragsize); 1054 800 } 1055 801
Note:
See TracChangeset
for help on using the changeset viewer.