Changeset 61523 in vbox
- Timestamp:
- Jun 7, 2016 9:47:21 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 12 edited
-
include/VBox/vmm/pdmaudioifs.h (modified) (4 diffs)
-
src/VBox/Devices/Audio/AudioMixBuffer.cpp (modified) (2 diffs)
-
src/VBox/Devices/Audio/AudioMixer.cpp (modified) (18 diffs)
-
src/VBox/Devices/Audio/AudioMixer.h (modified) (4 diffs)
-
src/VBox/Devices/Audio/DevIchAc97.cpp (modified) (22 diffs)
-
src/VBox/Devices/Audio/DevIchHda.cpp (modified) (36 diffs)
-
src/VBox/Devices/Audio/DevIchHdaCodec.cpp (modified) (7 diffs)
-
src/VBox/Devices/Audio/DrvAudio.cpp (modified) (23 diffs)
-
src/VBox/Devices/Audio/DrvHostALSAAudio.cpp (modified) (8 diffs)
-
src/VBox/Devices/Audio/DrvHostPulseAudio.cpp (modified) (2 diffs)
-
src/VBox/Devices/Audio/alsa_mangling.h (modified) (1 diff)
-
src/VBox/Devices/Audio/alsa_stubs.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/pdmaudioifs.h
r61413 r61523 173 173 /** Interleaved access, where the data can be 174 174 * mixed together with data of other audio streams. */ 175 PDMAUDIOSTREAMLAYOUT_INTERLEAVED 175 PDMAUDIOSTREAMLAYOUT_INTERLEAVED, 176 /** Hack to blow the type up to 32-bit. */ 177 PDMAUDIOSTREAMLAYOUT_32BIT_HACK = 0x7fffffff 176 178 } PDMAUDIOSTREAMLAYOUT, *PPDMAUDIOSTREAMLAYOUT; 177 179 … … 716 718 717 719 /** 718 * Plays (transfers) a ll available audio samples of a an output stream via the connected host backend.720 * Plays (transfers) available audio samples via the host backend. Only works with output streams. 719 721 * 720 722 * @returns VBox status code. … … 723 725 */ 724 726 DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed)); 727 728 /** 729 * Captures (transfers) available audio samples from the host backend. Only works with input streams. 730 * 731 * @returns VBox status code. 732 * @param pInterface Pointer to the interface structure containing the called function pointer. 733 * @param pcSamplesCaptured Number of samples captured. Optional. 734 */ 735 DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured)); 725 736 726 737 #ifdef VBOX_WITH_AUDIO_CALLBACKS … … 732 743 733 744 /** PDMIAUDIOCONNECTOR interface ID. */ 734 #define PDMIAUDIOCONNECTOR_IID " 9C097435-3276-4D88-A49A-A4FE671D86F8"745 #define PDMIAUDIOCONNECTOR_IID "D1B6465D-E3DD-455B-9E05-FB6D56F7D472" 735 746 736 747 -
trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
r61409 r61523 21 21 #ifdef DEBUG_andy 22 22 /* 23 * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data24 * to a file on the host. Be sure to adjust DEBUG_DUMP_PCM_DATA_PATH23 * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data 24 * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH 25 25 * to your needs before using this! 26 26 */ … … 243 243 pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear)); 244 244 245 Assert(cSamplesToClear <= pIter->cMixed);246 245 pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear); 247 246 } -
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r61386 r61523 341 341 } 342 342 else 343 { 344 AssertMsgFailed(("Direction not implemented\n")); 345 rc = VERR_NOT_IMPLEMENTED; 346 } 343 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 347 344 #else 348 345 rc = VINF_SUCCESS; … … 455 452 } 456 453 457 int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enm Cmd)454 int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmSinkCmd) 458 455 { 459 456 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 460 457 461 PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enm Cmd);458 PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmSinkCmd); 462 459 if (enmCmdStream == PDMAUDIOSTREAMCMD_UNKNOWN) 463 460 return VERR_NOT_SUPPORTED; … … 474 471 } 475 472 476 LogFlowFunc(("[%s]: enmCmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc)); 473 /* Remove dirty bit in any case. */ 474 pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY; 475 476 if (enmSinkCmd == AUDMIXSINKCMD_ENABLE) 477 pSink->fStatus |= AUDMIXSINK_STS_RUNNING; 478 else if (enmSinkCmd == AUDMIXSINKCMD_DISABLE) 479 pSink->fStatus &= ~AUDMIXSINK_STS_RUNNING; 480 481 LogFlowFunc(("[%s]: enmCmd=%ld, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pSink->fStatus, rc)); 477 482 return rc; 478 483 } … … 557 562 } 558 563 564 AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink) 565 { 566 if (!pSink) 567 return false; 568 569 LogFlowFunc(("[%s]: fStatus=0x%x\n", pSink->pszName, pSink->fStatus)); 570 571 /* If the dirty flag is set, there is unprocessed data in the sink. */ 572 return pSink->fStatus; 573 } 574 559 575 uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink) 560 576 { … … 563 579 564 580 return pSink->cStreams; 565 }566 567 bool AudioMixerSinkHasData(PAUDMIXSINK pSink)568 {569 if (!pSink)570 return false;571 572 LogFlowFunc(("[%s]: %RTbool\n", pSink->pszName, (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY)));573 574 /* If the dirty flag is set, there is unprocessed data in the sink. */575 return (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY);576 581 } 577 582 … … 588 593 ("Can't read from a sink which is not an input sink\n")); 589 594 595 #ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF 590 596 uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf); 591 597 if (!pvMixBuf) 592 598 return VERR_NO_MEMORY; 599 #endif 593 600 594 601 int rc = VERR_NOT_FOUND; 595 602 uint32_t cbRead = 0; 596 603 604 /* Flag indicating whether this sink is in a 'clean' state, 605 * e.g. there is no more data to read from. */ 606 bool fClean = true; 607 597 608 PAUDMIXSTREAM pMixStream; 598 609 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) … … 602 613 603 614 uint32_t cbTotalRead = 0; 604 uint32_t cbToRead = cbBuf;615 uint32_t cbToRead = cbBuf; 605 616 606 617 while (cbToRead) … … 608 619 uint32_t cbReadStrm; 609 620 AssertPtr(pMixStream->pConn); 621 #ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF 610 622 rc = pMixStream->pConn->pfnStreamRead(pMixStream->pConn, pMixStream->pStream, 611 623 (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm); 624 #endif 612 625 if ( RT_FAILURE(rc) 613 626 || !cbReadStrm) … … 625 638 626 639 cbRead = RT_MAX(cbRead, cbTotalRead); 640 641 PDMAUDIOSTRMSTS strmSts = pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream); 642 fClean &= !(strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE); 627 643 } 628 644 629 645 if (RT_SUCCESS(rc)) 630 646 { 631 memcpy(pvBuf, pvMixBuf, cbRead); /* @todo Use an intermediate mixing buffer per sink! */ 632 647 if (fClean) 648 pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY; 649 650 #ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF 651 if (cbRead) 652 memcpy(pvBuf, pvMixBuf, cbRead); 653 #endif 633 654 if (pcbRead) 634 655 *pcbRead = cbRead; 635 656 } 636 657 658 #ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF 637 659 RTMemFree(pvMixBuf); 638 639 Log3Func(("[%s]: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc)); 660 #endif 661 662 Log3Func(("[%s]: cbRead=%RU32, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, cbRead, pSink->fStatus, rc)); 640 663 return rc; 641 664 } … … 644 667 { 645 668 AssertPtrReturn(pSink, VERR_INVALID_PARAMETER); 646 if (!pStream) 669 if ( !pStream 670 || !pStream->pSink) /* Not part of a sink anymore? */ 671 { 647 672 return VERR_NOT_FOUND; 673 } 648 674 649 675 AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n", 650 pStream->pszName, pSink->pszName), VERR_NOT_FOUND);676 pStream->pszName, pSink->pszName), VERR_NOT_FOUND); 651 677 652 678 LogFlowFunc(("[%s]: (Stream = %s), cStreams=%RU8\n", … … 660 686 /* Remove stream from sink. */ 661 687 RTListNodeRemove(&pStream->Node); 662 Assert(pSink->cStreams);663 pSink->cStreams--;664 688 665 689 /* Set sink to NULL so that we know we're not part of any sink anymore. */ … … 671 695 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 672 696 { 673 audioMixerSinkRemoveStreamInternal(pSink, pStream); 697 int rc = audioMixerSinkRemoveStreamInternal(pSink, pStream); 698 if (RT_SUCCESS(rc)) 699 { 700 Assert(pSink->cStreams); 701 pSink->cStreams--; 702 } 674 703 } 675 704 … … 763 792 } 764 793 765 void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed , uint32_t *pcbData)794 void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed) 766 795 { 767 796 AssertPtrReturnVoid(pSink); 768 /* pcbData is optional. */769 797 770 798 /* Note: cTimerTicks / cTicksElapsed = Hz elapsed. */ 771 799 772 LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64\n", pSink->pszName, cTimerTicks, cTicksElapsed)); 773 774 // uint32_t cSamplesMin = (uint32_t)((2 * cTicksElapsed * pSink->PCMProps.uHz + cTimerTicks) / cTimerTicks / 2); 775 uint32_t cSamplesMin = (cTicksElapsed / pSink->PCMProps.uHz) * pSink->PCMProps.cChannels; 776 // cSamplesMin = (uint32_t)((2 * cTicksElapsed * 44100 + cTimerTicks) / cTimerTicks / 2); 777 uint32_t cbSamplesMin = _4K; //cSamplesMin << pSink->PCMProps.cShift; 778 779 //Assert((cbSamplesMin % 2 == 0)); 780 781 //LogFlowFunc(("[%s]: cSamplesMin=%RU32 (%RU32 bytes, %RU32Hz)\n", pSink->pszName, cSamplesMin, cbSamplesMin, pSink->PCMProps.uHz)); 782 783 uint32_t cbData = cbSamplesMin; 784 785 if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT) 786 { 787 // uint32_t cSinkSamplesLive = AudioMixBufAvail(&pSink->MixBuf); 788 // if (!cSinkSamplesLive) 789 // cbData = AUDIOMIXBUF_S2B_RATIO(&pSink->MixBuf, AudioMixBufFree(&pSink->MixBufGuest)); 790 } 800 LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64 -> %zuHz\n", 801 pSink->pszName, cTimerTicks, cTicksElapsed, cTimerTicks / cTicksElapsed)); 791 802 792 803 audioMixerSinkUpdateInternal(pSink); 793 794 if (pcbData)795 *pcbData = cbData;796 804 } 797 805 … … 810 818 AssertPtr(pStream); 811 819 812 uint32_t cPlayed = 0; 813 814 rc = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream); 815 if (RT_SUCCESS(rc)) 820 uint32_t cPlayed = 0; 821 uint32_t cCaptured = 0; 822 823 int rc2 = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream); 824 if (RT_SUCCESS(rc2)) 816 825 { 817 826 if (pStream->enmDir == PDMAUDIODIR_IN) 818 827 { 819 /** @todo Implement this! */ 820 #if 0 821 rc = pStream->pConn->pfnStreamCapture(pStream->pConn, NULL /* pcSamplesCaptured */); 822 #endif 828 rc = pMixStream->pConn->pfnStreamCapture(pMixStream->pConn, pMixStream->pStream, &cCaptured); 829 if (RT_FAILURE(rc2)) 830 { 831 LogFlowFunc(("%s: Failed capture stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2)); 832 if (RT_SUCCESS(rc)) 833 rc = rc2; 834 } 835 836 if (cCaptured) 837 pSink->fStatus |= AUDMIXSINK_STS_DIRTY; 838 } 839 else if (pStream->enmDir == PDMAUDIODIR_OUT) 840 { 841 rc2 = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed); 842 if (RT_FAILURE(rc2)) 843 { 844 LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2)); 845 if (RT_SUCCESS(rc)) 846 rc = rc2; 847 } 823 848 } 824 849 else 825 { 826 rc = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed); 827 if (RT_FAILURE(rc)) 828 LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc)); 829 } 850 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 830 851 } 831 852 832 Log3Func(("\t%s: cPlayed=%RU32, rc=%Rrc\n", pMixStream->pStream->szName, cPlayed, rc)); 833 } 853 Log3Func(("\t%s: cPlayed=%RU32, cCaptured=%RU32\n", pMixStream->pStream->szName, cPlayed, cCaptured)); 854 } 855 856 if (RT_FAILURE(rc)) 857 LogFlowFunc(("Failed with rc=%Rrc\n", rc)); 834 858 835 859 return rc; … … 914 938 } 915 939 916 /* Set dirty bit. */ 917 pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY; 940 if (cbBuf) 941 { 942 /* Set dirty bit. */ 943 pSink->fStatus |= AUDMIXSINK_STS_DIRTY; 944 } 918 945 919 946 if (pcbWritten) … … 975 1002 int rc; 976 1003 977 if (pMixStream->pSink) 1004 if (pMixStream->pSink) /* Is the stream part of a sink? */ 978 1005 { 979 1006 /* Save sink pointer, as after audioMixerSinkRemoveStreamInternal() the … … 981 1008 PAUDMIXSINK pSink = pMixStream->pSink; 982 1009 983 rc = audioMixerSinkRemoveStreamInternal(p MixStream->pSink, pMixStream);1010 rc = audioMixerSinkRemoveStreamInternal(pSink, pMixStream); 984 1011 if (RT_SUCCESS(rc)) 985 1012 { 986 AssertPtr(pSink);987 1013 Assert(pSink->cStreams); 988 1014 pSink->cStreams--; … … 994 1020 if (RT_SUCCESS(rc)) 995 1021 audioMixerStreamDestroyInternal(pMixStream); 1022 1023 LogFlowFunc(("Returning %Rrc\n", rc)); 996 1024 } 997 1025 -
trunk/src/VBox/Devices/Audio/AudioMixer.h
r61166 r61523 68 68 } AUDMIXSTREAM, *PAUDMIXSTREAM; 69 69 70 /** No flags specified. */ 71 #define AUDMIXSINK_FLAG_NONE 0 72 /** Dirty flag. */ 73 #define AUDMIXSINK_FLAG_DIRTY RT_BIT(0) 70 /** Defines an audio sink's current status. */ 71 #define AUDMIXSINKSTS uint32_t 72 73 /** No status specified. */ 74 #define AUDMIXSINK_STS_NONE 0 75 /** The sink is active and running. */ 76 #define AUDMIXSINK_STS_RUNNING RT_BIT(0) 77 /** Dirty flag. 78 * For output sinks this means that there is data in the 79 * sink which has not been played yet. 80 * For input sinks this means that there is data in the 81 * sink which has been recorded but not transferred to the 82 * destination yet. */ 83 #define AUDMIXSINK_STS_DIRTY RT_BIT(1) 74 84 75 85 /** … … 117 127 * if this sink handles input or output. */ 118 128 AUDMIXSINKDIR enmDir; 119 /** Sink flags of type AUDMIXSINK_FLAG_. */120 uint32_t fFlags;129 /** Sink status of type AUDMIXSINK_STS_XXX. */ 130 AUDMIXSINKSTS fStatus; 121 131 /** The sink's PCM format. */ 122 132 PDMPCMPROPS PCMProps; … … 170 180 AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink); 171 181 PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex); 182 AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink); 172 183 uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink); 173 bool AudioMixerSinkHasData(PAUDMIXSINK pSink);174 184 int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead); 175 185 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); … … 177 187 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps); 178 188 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol); 179 void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed , uint32_t *pcbData);189 void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed); 180 190 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 181 191 int AudioMixerSinkUpdate(PAUDMIXSINK pSink); -
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r61399 r61523 46 46 *********************************************************************************************************************************/ 47 47 48 #ifdef DEBUG 49 //#define DEBUG_LUN 50 # ifdef DEBUG_LUN 51 # define DEBUG_LUN_NUM 1 48 #ifdef DEBUG_andy 49 /* 50 * AC97_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data 51 * to a file on the host. Be sure to adjust AC97_DEBUG_DUMP_PCM_DATA_PATH 52 * to your needs before using this! 53 */ 54 # define AC97_DEBUG_DUMP_PCM_DATA 55 # ifdef RT_OS_WINDOWS 56 # define AC97_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\" 57 # else 58 # define AC97_DEBUG_DUMP_PCM_DATA_PATH "/tmp/" 52 59 # endif 53 #endif /* DEBUG */60 #endif /* DEBUG_andy */ 54 61 55 62 #define AC97_SSM_VERSION 1 … … 76 83 #define CR_IOCE RT_BIT(4) /* rw, Interrupt On Completion Enable. */ 77 84 #define CR_FEIE RT_BIT(3) /* rw FIFO Error Interrupt Enable. */ 78 #define CR_LVBIE RT_BIT(2) /* rw */79 #define CR_RR RT_BIT(1) /* rw */80 #define CR_RPBM RT_BIT(0) /* rw */85 #define CR_LVBIE RT_BIT(2) /* rw Last Valid Buffer Interrupt Enable. */ 86 #define CR_RR RT_BIT(1) /* rw Reset Registers. */ 87 #define CR_RPBM RT_BIT(0) /* rw Run/Pause Bus Master. */ 81 88 #define CR_VALID_MASK (RT_BIT(5) - 1) 82 89 #define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE) … … 263 270 uint8_t lvi; /** rw 0, Last valid index. */ 264 271 uint16_t sr; /** rw 1, Status register. */ 265 uint16_t picb; /** ro 0, Position in current buffer . */272 uint16_t picb; /** ro 0, Position in current buffer (in samples). */ 266 273 uint8_t piv; /** ro 0, Prefetched index value. */ 267 274 uint8_t cr; /** rw 0, Control register. */ … … 423 430 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser); 424 431 #endif 425 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream , uint32_t cbElapsed);432 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream); 426 433 427 434 static void ichac97WarmReset(PAC97STATE pThis) … … 532 539 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 533 540 534 bool fActive = AudioMixerSink HasData(ichac97IndexToSink(pThis, pStream->u8Strm));541 bool fActive = AudioMixerSinkGetStatus(ichac97IndexToSink(pThis, pStream->u8Strm)); 535 542 536 543 LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8Strm, fActive)); … … 1145 1152 * @param pcbWritten 1146 1153 */ 1147 static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cb Max, uint32_t *pcbWritten)1154 static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten) 1148 1155 { 1149 1156 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1150 1157 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1151 AssertReturn(cb Max,VERR_INVALID_PARAMETER);1158 AssertReturn(cbToWrite, VERR_INVALID_PARAMETER); 1152 1159 /* pcbWritten is optional. */ 1153 1160 … … 1158 1165 uint32_t cbWrittenTotal = 0; 1159 1166 1160 Log3Func(("PICB=%RU16, cbMax=%RU32\n", pRegs->picb, cb Max));1161 1162 uint32_t cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbMax); /** @todo r=andy Assumes 16bit sample size. */1167 Log3Func(("PICB=%RU16, cbMax=%RU32\n", pRegs->picb, cbToWrite)); 1168 1169 cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */ 1163 1170 if (!cbToWrite) 1164 1171 { … … 1170 1177 int rc = VINF_SUCCESS; 1171 1178 1172 LogFlowFunc(("pReg =%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbMax, cbToWrite));1179 LogFlowFunc(("pRegs=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbToWrite, cbToWrite)); 1173 1180 1174 1181 Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW); … … 1182 1189 PDMDevHlpPhysRead(pDevIns, addr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */ 1183 1190 1184 #if defined (RT_OS_LINUX) && defined(DEBUG_andy)1191 #ifdef AC97_DEBUG_DUMP_PCM_DATA 1185 1192 RTFILE fh; 1186 RTFileOpen(&fh, "/tmp/ac97WriteAudio.pcm",1193 RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm", 1187 1194 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 1188 1195 RTFileWrite(fh, pu8FIFOW, cbToRead, NULL); … … 1234 1241 static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed) 1235 1242 { 1243 LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed)); 1244 1236 1245 if (!(pThis->bup_flag & BUP_SET)) 1237 1246 { … … 1240 1249 unsigned int i; 1241 1250 uint32_t *p = (uint32_t*)pThis->silence; 1242 for (i = 0; i < sizeof(pThis->silence) / 4; i++) 1251 for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */ 1243 1252 *p++ = pThis->last_samp; 1244 1253 } … … 1269 1278 } 1270 1279 1271 static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cb Max, uint32_t *pcbRead)1280 static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead) 1272 1281 { 1273 1282 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1274 1283 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1275 AssertReturn(cb Max,VERR_INVALID_PARAMETER);1284 AssertReturn(cbToRead, VERR_INVALID_PARAMETER); 1276 1285 /* pcbRead is optional. */ 1277 1286 … … 1285 1294 1286 1295 uint32_t cbRead = 0; 1287 uint32_t cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1), 1288 RT_MIN(pStream->State.cbFIFOW, cbMax)); /** @todo r=andy Assumes 16bit samples. */ 1296 1297 cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1), 1298 RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */ 1289 1299 1290 1300 if (!cbToRead) … … 1365 1375 uint64_t cTicksPerSec = TMTimerGetFreq(pTimer); 1366 1376 1377 LogFlowFuncEnter(); 1378 1367 1379 /* Update current time timestamp. */ 1368 1380 pThis->uTimerTS = cTicksNow; 1369 1381 1370 LogFlowFuncEnter(); 1371 1372 uint32_t cbLineIn; 1373 AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksPerSec, &cbLineIn); 1374 if (cbLineIn) 1375 ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbLineIn); 1376 1377 uint32_t cbMicIn; 1378 AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksPerSec, &cbMicIn); 1379 if (cbMicIn) 1380 ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbMicIn); 1381 1382 uint32_t cbOut; 1383 AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksPerSec, &cbOut); 1384 if (cbOut) 1385 ichac97TransferAudio(pThis, &pThis->StreamOut, cbOut); 1382 /* Flag indicating whether to kick the timer again for a 1383 * new data processing round. */ 1384 bool fKickTimer = false; 1385 1386 AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksPerSec); 1387 ichac97TransferAudio(pThis, &pThis->StreamLineIn); 1388 1389 fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY; 1390 1391 AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksPerSec); 1392 ichac97TransferAudio(pThis, &pThis->StreamMicIn); 1393 1394 fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY; 1395 1396 AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksPerSec); 1397 ichac97TransferAudio(pThis, &pThis->StreamOut); 1398 1399 fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkOutput) & AUDMIXSINK_STS_DIRTY; 1386 1400 1387 1401 if ( ASMAtomicReadBool(&pThis->fTimerActive) 1388 || AudioMixerSinkHasData(pThis->pSinkLineIn) 1389 || AudioMixerSinkHasData(pThis->pSinkMicIn) 1390 || AudioMixerSinkHasData(pThis->pSinkOutput)) 1402 || fKickTimer) 1391 1403 { 1392 1404 /* Kick the timer again. */ … … 1401 1413 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */ 1402 1414 1403 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream , uint32_t cbElapsed)1404 { 1405 Log3Func(("SD=%RU8 , cbElapsed=%RU32\n", pStream->u8Strm , cbElapsed));1415 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream) 1416 { 1417 Log3Func(("SD=%RU8\n", pStream->u8Strm)); 1406 1418 1407 1419 PAC97BMREGS pRegs = &pStream->Regs; … … 1409 1421 if (pRegs->sr & SR_DCH) /* Controller halted? */ 1410 1422 { 1411 if (pRegs->cr & CR_RPBM) 1423 if (pRegs->cr & CR_RPBM) /* Bus master operation starts. */ 1412 1424 { 1413 1425 switch (pStream->u8Strm) 1414 1426 { 1415 1427 case PO_INDEX: 1416 ichac97WriteBUP(pThis, cbElapsed);1428 ichac97WriteBUP(pThis, (uint32_t)(pRegs->picb << 1)); 1417 1429 break; 1418 1430 … … 1432 1444 uint32_t cbWrittenTotal = 0; 1433 1445 1434 while (cbElapsed >> 1) /** @todo r=andy This assumes (hardcodes) 16bit sample size.*/1446 do 1435 1447 { 1436 1448 if (!pRegs->bd_valid) … … 1446 1458 if (pRegs->civ == pRegs->lvi) 1447 1459 { 1448 pRegs->sr |= SR_DCH; /* CELV? */1460 pRegs->sr |= SR_DCH; /** @todo r=andy Also set CELV? */ 1449 1461 pThis->bup_flag = 0; 1450 1462 … … 1461 1473 } 1462 1474 1463 uint32_t cbT ransferred;1475 uint32_t cbToTransfer, cbTransferred; 1464 1476 switch (pStream->u8Strm) 1465 1477 { 1466 1478 case PO_INDEX: 1467 1479 { 1468 rc = ichac97WriteAudio(pThis, pStream, cbElapsed, &cbTransferred); 1480 cbToTransfer = (uint32_t)(pRegs->picb << 1); 1481 1482 rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred); 1469 1483 if ( RT_SUCCESS(rc) 1470 1484 && cbTransferred) 1471 1485 { 1472 1486 cbWrittenTotal += cbTransferred; 1473 Assert(cbElapsed >= cbTransferred); 1474 cbElapsed -= cbTransferred; 1475 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */ 1487 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */ 1476 1488 pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */ 1477 1489 } … … 1482 1494 case MC_INDEX: 1483 1495 { 1484 rc = ichac97ReadAudio(pThis, pStream, cbElapsed, &cbTransferred); 1496 cbToTransfer = (uint32_t)(pRegs->picb << 1); 1497 1498 rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred); 1485 1499 if ( RT_SUCCESS(rc) 1486 1500 && cbTransferred) 1487 1501 { 1488 Assert(cbElapsed >= cbTransferred); 1489 cbElapsed -= cbTransferred; 1490 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */ 1502 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */ 1491 1503 pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */ 1492 1504 } … … 1532 1544 } 1533 1545 1534 if ( RT_FAILURE(rc) 1535 || rc == VINF_EOF) /* All data processed? */ 1536 { 1537 break; 1538 } 1539 } 1546 if (rc == VINF_EOF) /* All data processed? */ 1547 break; 1548 1549 } while (RT_SUCCESS(rc)); 1540 1550 1541 1551 LogFlowFuncLeaveRC(rc); … … 1549 1559 uint32_t *pu32Val, unsigned cbVal) 1550 1560 { 1551 PAC97STATE pThis = (PAC97STATE)pvUser;1561 PAC97STATE pThis = (PAC97STATE)pvUser; 1552 1562 1553 1563 /* Get the index of the NABMBAR port. */ -
trunk/src/VBox/Devices/Audio/DevIchHda.cpp
r61417 r61523 58 58 59 59 #ifdef DEBUG_andy 60 /* 61 * HDA_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data 62 * to a file on the host. Be sure to adjust HDA_DEBUG_DUMP_PCM_DATA_PATH 63 * to your needs before using this! 64 */ 65 # define HDA_DEBUG_DUMP_PCM_DATA 66 # ifdef RT_OS_WINDOWS 67 # define HDA_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\" 68 # else 69 # define HDA_DEBUG_DUMP_PCM_DATA_PATH "/tmp/" 70 # endif 71 60 72 /* Enables experimental support for separate mic-in handling. 61 73 Do not enable this yet for regular builds, as this needs more testing first! */ … … 930 942 static int hdaStreamStop(PHDASTREAM pStream); 931 943 static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout); 932 static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream , uint32_t cbToProcess, uint32_t *pcbProcessed);944 static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream); 933 945 #endif 934 946 … … 1756 1768 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1757 1769 1758 bool fActive = false; 1759 1760 AssertPtr(pStream->pMixSink); 1761 if (pStream->pMixSink->pMixSink) 1762 fActive = AudioMixerSinkHasData(pStream->pMixSink->pMixSink); 1770 bool fActive = pStream->State.fActive; 1771 1772 if (!fActive) 1773 { 1774 AssertPtr(pStream->pMixSink); 1775 if (pStream->pMixSink->pMixSink) 1776 fActive = AudioMixerSinkGetStatus(pStream->pMixSink->pMixSink) & AUDMIXSINK_STS_DIRTY; 1777 } 1763 1778 1764 1779 LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive)); … … 1780 1795 ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE; 1781 1796 1782 /* First, enable or disable the stream 's sink, if any. */1797 /* First, enable or disable the stream and the stream's sink, if any. */ 1783 1798 if (pStream->pMixSink->pMixSink) 1784 1799 AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd); 1800 1801 pStream->State.fActive = fActive; 1785 1802 1786 1803 /* Second, see if we need to start or stop the timer. */ … … 2723 2740 AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER); 2724 2741 2725 LogFlowFunc(("Stream=%s \n", pCfg->szName));2742 LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Source)); 2726 2743 2727 2744 int rc; … … 2731 2748 case PDMAUDIORECSOURCE_LINE: 2732 2749 { 2733 pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;2734 pCfg->cChannels = 2;2735 2750 rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN); 2736 2751 if (RT_SUCCESS(rc)) … … 2741 2756 case PDMAUDIORECSOURCE_MIC: 2742 2757 { 2743 pCfg->DestSource.Source = PDMAUDIORECSOURCE_MIC;2744 pCfg->cChannels = 2;2745 2758 rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN); 2746 2759 if (RT_SUCCESS(rc)) … … 2785 2798 /* Set audio direction. */ 2786 2799 strmCfg.enmDir = hdaGetDirFromSD(pStream->u8SD); 2800 switch (strmCfg.enmDir) 2801 { 2802 case PDMAUDIODIR_IN: 2803 #ifdef VBOX_WITH_HDA_MIC_IN 2804 # error "Implement me!" 2805 #else 2806 strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE; 2807 #endif 2808 break; 2809 2810 case PDMAUDIODIR_OUT: 2811 /* Destination(s) will be set in hdaAddStreamOut(), 2812 * based on the channels / stream layout. */ 2813 break; 2814 2815 default: 2816 rc = VERR_NOT_SUPPORTED; 2817 break; 2818 } 2787 2819 2788 2820 /* … … 2794 2826 * number of channels in a single audio stream. 2795 2827 */ 2796 rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg); 2797 AssertRC(rc); 2828 if (RT_SUCCESS(rc)) 2829 { 2830 rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg); 2831 AssertRC(rc); 2832 } 2798 2833 2799 2834 if (RT_SUCCESS(rc)) … … 3169 3204 3170 3205 /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */ 3171 //cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));3206 cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS)); 3172 3207 3173 3208 /* Make sure we only transfer as many bytes as requested. */ … … 3447 3482 * but "reports bytes" when all conditions are met (FIFOW). 3448 3483 */ 3449 static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cb Max, uint32_t *pcbRead)3484 static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed) 3450 3485 { 3451 3486 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 3452 3487 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 3453 /* pcb Read is optional. */3488 /* pcbProcessed is optional. */ 3454 3489 3455 3490 int rc; … … 3460 3495 PHDABDLE pBDLE = &pStream->State.BDLE; 3461 3496 3462 uint32_t cbBuf = hdaStreamGetTransferSize(pThis, pStream, cbMax); 3463 Log3Func(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE)); 3464 3465 if (!cbBuf) 3497 if (!cbToProcess) 3466 3498 { 3467 3499 rc = VINF_EOF; … … 3471 3503 AssertPtr(pStream->pMixSink); 3472 3504 AssertPtr(pStream->pMixSink->pMixSink); 3473 rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cb Buf, &cbRead);3505 rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToProcess, &cbRead); 3474 3506 if (RT_FAILURE(rc)) 3475 3507 break; … … 3482 3514 3483 3515 /* Sanity checks. */ 3484 Assert(cbRead <= cbBuf); 3516 Assert(cbRead <= cbToProcess); 3517 Assert(cbRead <= sizeof(pBDLE->State.au8FIFO)); 3485 3518 Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff); 3486 3519 … … 3515 3548 if (RT_SUCCESS(rc)) 3516 3549 { 3517 if (pcbRead) 3518 *pcbRead = cbRead; 3519 } 3520 3521 Log3Func(("Returning cbRead=%RU32, rc=%Rrc\n", cbRead, rc)); 3550 if (pcbProcessed) 3551 *pcbProcessed = cbRead; 3552 } 3553 3554 if (RT_FAILURE(rc)) 3555 LogFlowFunc(("Failed with %Rrc\n", rc)); 3556 3522 3557 return rc; 3523 3558 } 3524 3559 3525 static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cb Max, uint32_t *pcbWritten)3560 static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed) 3526 3561 { 3527 3562 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 3528 3563 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 3529 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);3530 3564 /* pcbWritten is optional. */ 3531 3565 … … 3533 3567 3534 3568 uint32_t cbWritten = 0; 3535 uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbMax);3536 3537 Log3Func(("cbToWrite=%RU32, %R[bdle]\n", cbToWrite, pBDLE));3538 3569 3539 3570 /* … … 3542 3573 */ 3543 3574 int rc; 3544 if (!cbTo Write)3575 if (!cbToProcess) 3545 3576 { 3546 3577 rc = VINF_EOF; … … 3549 3580 { 3550 3581 void *pvBuf = pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW; 3551 Assert(cbTo Write>= pBDLE->State.cbBelowFIFOW);3552 uint32_t cbBuf = cbTo Write- pBDLE->State.cbBelowFIFOW;3582 Assert(cbToProcess >= pBDLE->State.cbBelowFIFOW); 3583 uint32_t cbBuf = cbToProcess - pBDLE->State.cbBelowFIFOW; 3553 3584 3554 3585 /* … … 3559 3590 pvBuf, cbBuf); 3560 3591 AssertRC(rc); 3561 #if defined (RT_OS_LINUX) && defined(DEBUG_andy) 3592 3593 #ifdef HDA_DEBUG_DUMP_PCM_DATA 3562 3594 RTFILE fh; 3563 RTFileOpen(&fh, "/tmp/hdaWriteAudio-hda.pcm",3595 RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio-hda.pcm", 3564 3596 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 3565 3597 RTFileWrite(fh, pvBuf, cbBuf, NULL); … … 3642 3674 /* Always report all data as being written; 3643 3675 * backends who were not able to catch up have to deal with it themselves. */ 3644 cbWritten = cbTo Write;3645 3646 hdaBDLEUpdate(pBDLE, cbTo Write, cbWritten);3676 cbWritten = cbToProcess; 3677 3678 hdaBDLEUpdate(pBDLE, cbToProcess, cbWritten); 3647 3679 } 3648 3680 else … … 3663 3695 if (RT_SUCCESS(rc)) 3664 3696 { 3665 if (pcbWritten) 3666 *pcbWritten = cbWritten; 3667 } 3668 3669 Log3Func(("Returning cbMax=%RU32, cbWritten=%RU32, rc=%Rrc\n", cbMax, cbWritten, rc)); 3697 if (pcbProcessed) 3698 *pcbProcessed = cbWritten; 3699 } 3700 3701 if (RT_FAILURE(rc)) 3702 LogFlowFunc(("Failed with %Rrc\n", rc)); 3703 3670 3704 return rc; 3671 3705 } … … 3904 3938 } 3905 3939 3906 if (pMixStream) 3907 { 3908 AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream); 3909 AudioMixerStreamDestroy(pMixStream); 3910 } 3940 AssertPtr(pMixStream); 3941 3942 AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream); 3943 AudioMixerStreamDestroy(pMixStream); 3911 3944 } 3912 3945 … … 4068 4101 uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS; 4069 4102 4103 LogFlowFuncEnter(); 4104 4070 4105 /* Update current time timestamp. */ 4071 4106 pThis->uTimerTS = cTicksNow; 4107 4108 /* Flag indicating whether to kick the timer again for a 4109 * new data processing round. */ 4110 bool fKickTimer = false; 4072 4111 4073 4112 PHDASTREAM pStreamLineIn = hdaGetStreamFromSink(pThis, &pThis->SinkLineIn); … … 4080 4119 #endif 4081 4120 4082 uint32_t cbLineIn; 4083 AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink, pThis->cTimerTicks, cTicksElapsed, &cbLineIn); 4084 if (cbLineIn) 4085 hdaTransfer(pThis, pStreamLineIn, cbLineIn, NULL); /** @todo Add rc! */ 4121 AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink, pThis->cTimerTicks, cTicksElapsed); 4122 hdaTransfer(pThis, pStreamLineIn); 4123 4124 if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY) 4125 fKickTimer = true; 4086 4126 4087 4127 #ifdef VBOX_WITH_HDA_MIC_IN 4088 uint32_t cbMicIn; 4089 AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink , pThis->cTimerTicks, cTicksElapsed, &cbMicIn); 4090 #endif 4091 4092 uint32_t cbFront; 4093 AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink, pThis->cTimerTicks, cTicksElapsed, &cbFront); 4128 AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink, pThis->cTimerTicks, cTicksElapsed); 4129 hdaTransfer(pThis, pStreamMicIn); 4130 4131 if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY) 4132 fKickTimer = true; 4133 #endif 4134 4135 AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink, pThis->cTimerTicks, cTicksElapsed); 4136 hdaTransfer(pThis, pStreamFront); 4137 4138 if (AudioMixerSinkGetStatus(pThis->SinkFront.pMixSink) & AUDMIXSINK_STS_DIRTY) 4139 fKickTimer = true; 4140 4094 4141 #ifdef VBOX_WITH_HDA_51_SURROUND 4095 uint32_t cbCenterLFE; 4096 AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed, &cbCenterLFE); 4097 uint32_t cbRear; 4098 AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink, pThis->cTimerTicks, cTicksElapsed, &cbRear); 4099 #endif 4100 4101 if (cbFront) 4102 hdaTransfer(pThis, pStreamFront, cbFront, NULL); /** @todo Add rc! */ 4142 AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed); 4143 AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink, pThis->cTimerTicks, cTicksElapsed); 4144 4145 /** @todo Check for stream interleaving and only call hdaTransfer() if required! */ 4146 #endif 4147 4103 4148 #ifdef VBOX_WITH_HDA_51_SURROUND 4104 4149 /* … … 4110 4155 4111 4156 if ( ASMAtomicReadBool(&pThis->fTimerActive) 4112 || AudioMixerSinkHasData(pThis->SinkFront.pMixSink) 4113 #ifdef VBOX_WITH_HDA_51_SURROUND 4114 || AudioMixerSinkHasData(pThis->SinkCenterLFE.pMixSink) 4115 || AudioMixerSinkHasData(pThis->SinkRear.pMixSink) 4116 #endif 4117 || AudioMixerSinkHasData(pThis->SinkLineIn.pMixSink)) 4157 || fKickTimer) 4118 4158 { 4119 4159 /* Kick the timer again. */ … … 4122 4162 TMTimerSet(pThis->pTimer, cTicksNow + cTicks); 4123 4163 } 4164 4165 LogFlowFuncLeave(); 4124 4166 4125 4167 STAM_PROFILE_STOP(&pThis->StatTimer, a); … … 4176 4218 #endif /* VBOX_WITH_AUDIO_CALLBACKS */ 4177 4219 4178 static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream , uint32_t cbToProcess, uint32_t *pcbProcessed)4220 static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream) 4179 4221 { 4180 4222 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 4181 4223 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 4182 /* pcbProcessed is optional. */4183 4224 4184 4225 if (ASMAtomicReadBool(&pThis->fInReset)) /* HDA controller in reset mode? Bail out. */ 4185 4226 { 4186 LogFlowFunc(("In reset mode, skipping\n")); 4187 4188 if (pcbProcessed) 4189 *pcbProcessed = 0; 4227 LogFlowFunc(("HDA in reset mode, skipping\n")); 4190 4228 return VINF_SUCCESS; 4191 4229 } … … 4196 4234 return rc; 4197 4235 4236 Log3Func(("[SD%RU8] fActive=%RTbool\n", pStream->u8SD, pStream->State.fActive)); 4237 4198 4238 /* Stop request received? */ 4199 if (pStream->State.fDoStop) 4239 if ( !pStream->State.fActive 4240 || pStream->State.fDoStop) 4200 4241 { 4201 4242 pStream->State.fActive = false; … … 4209 4250 else if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))) 4210 4251 fProceed = false; 4211 /* Nothing to process? */4212 else if (!cbToProcess)4213 fProceed = false;4214 4252 4215 4253 if ((HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) … … 4221 4259 if (!fProceed) 4222 4260 { 4223 Log3Func(("[SD%RU8] Skipping\n", pStream->u8SD));4261 Log3Func(("[SD%RU8]: Skipping\n", pStream->u8SD)); 4224 4262 4225 4263 rc = RTSemMutexRelease(pStream->State.hMtx); 4226 4264 AssertRC(rc); 4227 4265 4228 if (pcbProcessed)4229 *pcbProcessed = 0;4230 4266 return VINF_SUCCESS; 4231 4267 } … … 4242 4278 Assert(u32LPIB <= pStream->u32CBL); 4243 4279 4244 uint32_t cbLeft = cbToProcess;4245 uint32_t cbTotal = 0;4246 4247 4280 bool fInterrupt = false; 4248 4281 4249 Log3Func(("cbLeft=%RU32\n", cbLeft)); 4250 4251 # define FOO4252 4253 #ifdef FOO4282 #ifdef DEBUG_andy 4283 # define DEBUG_SIMPLE 4284 #endif 4285 4286 #ifdef DEBUG_SIMPLE 4254 4287 uint8_t u8FIFO[_16K+1]; 4255 4288 size_t u8FIFOff = 0; 4256 4289 #endif 4257 4290 4291 uint32_t cbToProcess = 0; 4292 uint32_t cbProcessed = 0; 4293 uint32_t cbProcessedTotal = 0; 4294 4258 4295 /* Set the FIFORDY bit on the stream while doing the transfer. */ 4259 4296 HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY); 4260 4297 4261 while (cbLeft)4298 do 4262 4299 { 4263 4300 /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */ … … 4269 4306 } 4270 4307 4271 uint32_t cbProcessed = 0; 4308 cbToProcess = hdaStreamGetTransferSize(pThis, pStream, _4K /** @todo Fix this */); 4309 cbProcessed = 0; 4310 4272 4311 if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) 4273 rc = hdaReadAudio (pThis, pStream, cbLeft, &cbProcessed);4312 rc = hdaReadAudio(pThis, pStream, cbToProcess, &cbProcessed); 4274 4313 else 4275 4314 { 4276 #ifndef FOO4277 rc = hdaWriteAudio(pThis, pStream, cb Left, &cbProcessed);4315 #ifndef DEBUG_SIMPLE 4316 rc = hdaWriteAudio(pThis, pStream, cbToProcess, &cbProcessed); 4278 4317 #else 4279 uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cb Left);4318 uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbToProcess); 4280 4319 4281 4320 void *pvBuf = u8FIFO + u8FIFOff; … … 4290 4329 hdaBDLEUpdate(pBDLE, cbToWrite, cbToWrite); 4291 4330 4292 LogFlowFunc(("u8FIFOff=%zu, cbLeft=%RU32, cbToWrite=%RU32\n", u8FIFOff, cbLeft, cbToWrite));4293 4294 4331 u8FIFOff += cbToWrite; 4332 Assert((u8FIFOff & 1) == 0); 4295 4333 Assert(u8FIFOff <= sizeof(u8FIFO)); 4296 4334 … … 4304 4342 hdaStreamTransferUpdate(pThis, pStream, cbProcessed); 4305 4343 4306 Assert(cbLeft >= cbProcessed); 4307 cbLeft -= cbProcessed; 4308 cbTotal += cbProcessed; 4309 4310 LogFlowFunc(("cbProcessed=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n", 4311 cbProcessed, cbLeft, cbTotal, rc)); 4344 cbProcessedTotal += cbProcessed; 4312 4345 4313 4346 if (rc == VINF_EOF) … … 4316 4349 if (hdaStreamTransferIsComplete(pThis, pStream, &fInterrupt)) 4317 4350 break; 4318 } 4351 4352 } while (RT_SUCCESS(rc)); 4319 4353 4320 4354 /* Remove the FIFORDY bit again. */ 4321 4355 HDA_STREAM_REG(pThis, STS, pStream->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY); 4322 4356 4323 #ifdef FOO 4324 #if defined (RT_OS_LINUX) && defined(DEBUG_andy) 4357 LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbProcessedTotal, cbToProcess, rc)); 4358 4359 #ifdef DEBUG_SIMPLE 4360 # ifdef HDA_DEBUG_DUMP_PCM_DATA 4325 4361 RTFILE fh; 4326 RTFileOpen(&fh, "/tmp/hdaWriteAudio.pcm",4362 RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio.pcm", 4327 4363 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 4328 4364 RTFileWrite(fh, u8FIFO, u8FIFOff, NULL); 4329 4365 RTFileClose(fh); 4330 #endif4331 #if 1 4366 # endif 4367 4332 4368 AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, u8FIFO, u8FIFOff, 4333 4369 NULL /* pcbWritten */); 4334 #endif 4335 #endif 4336 4337 #ifdef FOO 4370 #endif /* DEBUG_SIMPLE */ 4371 4338 4372 if (fInterrupt) 4339 4373 { … … 4352 4386 4353 4387 hdaProcessInterrupt(pThis); 4354 }4355 #endif4356 4357 Log3Func(("Written %RU32 / %RU32 (left: %RU32), rc=%Rrc\n", cbTotal, cbToProcess, cbLeft, rc));4358 4359 if (RT_SUCCESS(rc))4360 {4361 if (pcbProcessed)4362 *pcbProcessed = cbTotal;4363 4388 } 4364 4389 -
trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp
r61126 r61523 267 267 #define CODEC_AMP_NUM_STEPS 0x7F 268 268 /** The initial gain offset (and when doing a node reset). */ 269 #define CODEC_AMP_OFF_INITIAL 0x 40269 #define CODEC_AMP_OFF_INITIAL 0x7F 270 270 /** The amplifier's gain step size. */ 271 271 #define CODEC_AMP_STEP_SIZE 0x2 … … 928 928 /* Default input amplifier capabilities. */ 929 929 pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE, 930 0 /* Step size */,930 CODEC_AMP_STEP_SIZE, 931 931 CODEC_AMP_NUM_STEPS, 932 0 /* Initial offset */);932 CODEC_AMP_OFF_INITIAL); 933 933 /* Default output amplifier capabilities. */ 934 934 pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE, … … 1003 1003 pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */ 1004 1004 1005 pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 13, 0)1005 pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0) 1006 1006 | CODEC_F00_09_CAP_POWER_CTRL 1007 1007 | CODEC_F00_09_CAP_CONNECTION_LIST … … 1062 1062 case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */ 1063 1063 { 1064 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG( false/*fPresent*/, CODEC_F09_ANALOG_NA);1064 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA); 1065 1065 1066 1066 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) … … 1087 1087 case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */ 1088 1088 { 1089 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG( true/*fPresent*/, CODEC_F09_ANALOG_NA);1089 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA); 1090 1090 1091 1091 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) … … 1111 1111 case STAC9220_NID_PIN_C: /* Rear Speaker. */ 1112 1112 { 1113 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG( true/*fPresent*/, CODEC_F09_ANALOG_NA);1113 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA); 1114 1114 1115 1115 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) … … 1135 1135 case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */ 1136 1136 { 1137 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG( false/*fPresent*/, CODEC_F09_ANALOG_NA);1137 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA); 1138 1138 1139 1139 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r61398 r61523 18 18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 19 19 * -------------------------------------------------------------------- 20 *21 * This code is based on: audio.c from QEMU AUDIO subsystem.22 *23 * QEMU Audio subsystem24 *25 * Copyright (c) 2003-2005 Vassili Karpov (malc)26 *27 * Permission is hereby granted, free of charge, to any person obtaining a copy28 * of this software and associated documentation files (the "Software"), to deal29 * in the Software without restriction, including without limitation the rights30 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell31 * copies of the Software, and to permit persons to whom the Software is32 * furnished to do so, subject to the following conditions:33 *34 * The above copyright notice and this permission notice shall be included in35 * all copies or substantial portions of the Software.36 *37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL40 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER41 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,42 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN43 * THE SOFTWARE.44 20 */ 45 21 #define LOG_GROUP LOG_GROUP_DRV_AUDIO … … 148 124 } 149 125 126 /** 127 * Returns the host stream part of an audio stream pair, or NULL 128 * if no host stream has been assigned / is not available. 129 * 130 * @returns IPRT status code. 131 * @param pStream Audio stream to retrieve host stream part for. 132 */ 150 133 inline PPDMAUDIOSTREAM drvAudioGetHostStream(PPDMAUDIOSTREAM pStream) 151 134 { … … 448 431 } 449 432 450 #if 1451 433 /** 452 434 * Writes VM audio output data from the guest stream into the host stream. … … 479 461 } 480 462 463 AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT, 464 ("Stream '%s' is not an output stream and therefore cannot be written to (direction is 0x%x)\n", 465 pStream->szName, pStream->enmDir)); 466 481 467 LogFlowFunc(("[%s]: cbBuf=%RU32\n", pStream->szName, cbBuf)); 482 468 … … 516 502 } 517 503 518 #if 0519 uint32_t cMixed = 0;520 if (RT_SUCCESS(rc))521 {522 /* Mix just written guest stream samples to the host immediately. */523 rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &cMixed);524 }525 #endif526 527 #if 0528 uint32_t cPlayed = 0;529 if (RT_SUCCESS(rc))530 {531 PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);532 if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)533 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cPlayed);534 }535 #endif536 537 #ifdef DEBUG_andy538 AssertRC(rc);539 #endif540 541 #if 0542 /*543 * Second, mix the guest mixing buffer with the host mixing544 * buffer so that the host backend can play the data lateron.545 */546 uint32_t cMixed;547 if ( RT_SUCCESS(rc)548 && cWritten)549 {550 rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &cMixed);551 }552 else553 cMixed = 0;554 555 if (RT_SUCCESS(rc))556 {557 /*558 * Return the number of samples which actually have been mixed559 * down to the parent, regardless how much samples were written560 * into the children buffer.561 */562 if (pcbWritten)563 *pcbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cMixed);564 }565 #else566 504 if (RT_SUCCESS(rc)) 567 505 { … … 569 507 *pcbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritten); 570 508 } 571 #endif572 509 573 510 LogFlowFunc(("cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n", … … 580 517 return rc; 581 518 } 582 #else583 static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut,584 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)585 {586 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);587 AssertPtrReturn(pThis, VERR_INVALID_POINTER);588 589 AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);590 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);591 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);592 /* pcbWritten is optional. */593 594 int rc = RTCritSectEnter(&pThis->CritSect);595 if (RT_FAILURE(rc))596 return rc;597 598 if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))599 {600 rc = RTCritSectLeave(&pThis->CritSect);601 AssertRC(rc);602 603 return VERR_NOT_AVAILABLE;604 }605 606 PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;607 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);608 609 AssertMsg(pGstStrmOut->pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,610 ("Writing to disabled host output stream \"%s\" not possible\n",611 pHstStrmOut->MixBuf.pszName));612 613 if (!AudioMixBufFreeBytes(&pGstStrmOut->MixBuf))614 {615 if (pcbWritten)616 *pcbWritten = 0;617 618 return RTCritSectLeave(&pThis->CritSect);619 }620 621 /*622 * First, write data from the device emulation into our623 * guest mixing buffer.624 */625 uint32_t cWritten;626 //rc = AudioMixBufWriteAt(&pGstStrmOut->MixBuf, 0 /* Offset in samples */, pvBuf, cbBuf, &cWritten);627 rc = AudioMixBufWriteCirc(&pGstStrmOut->MixBuf, pvBuf, cbBuf, &cWritten);628 if (rc == VINF_BUFFER_OVERFLOW)629 LogRel(("Audio: Lost audio samples from guest, expect stuttering audio output\n"));630 631 /*632 * Second, mix the guest mixing buffer with the host mixing633 * buffer so that the host backend can play the data lateron.634 */635 uint32_t cMixed;636 if ( RT_SUCCESS(rc)637 && cWritten)638 {639 rc = AudioMixBufMixToParent(&pGstStrmOut->MixBuf, cWritten, &cMixed);640 }641 else642 cMixed = 0;643 644 if (RT_SUCCESS(rc))645 {646 /*647 * Return the number of samples which actually have been mixed648 * down to the parent, regardless how much samples were written649 * into the children buffer.650 */651 if (pcbWritten)652 *pcbWritten = AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cMixed);653 }654 655 LogFlowFunc(("%s -> %s: cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",656 pGstStrmOut->MixBuf.pszName, pHstStrmOut->MixBuf.pszName, cbBuf, cWritten,657 AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten), cMixed, rc));658 659 int rc2 = RTCritSectLeave(&pThis->CritSect);660 if (RT_SUCCESS(rc))661 rc = rc2;662 663 return rc;664 }665 #endif666 519 667 520 static DECLCALLBACK(uint32_t) drvAudioStreamAddRef(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) … … 688 541 } 689 542 690 #if 1691 543 static DECLCALLBACK(int) drvAudioStreamIterate(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 692 544 { … … 725 577 726 578 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream); 579 AssertPtr(pHstStream); 727 580 PPDMAUDIOSTREAM pGstStream = pHstStream->pPair; 581 AssertPtr(pGstStream); 728 582 729 583 int rc = VINF_SUCCESS; … … 731 585 do 732 586 { 733 /*if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)) 734 break;*/ 587 uint32_t cSamplesMixed = 0; 735 588 736 589 PDMAUDIOSTRMSTS hstStrmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream); … … 738 591 if (pHstStream->enmDir == PDMAUDIODIR_IN) 739 592 { 740 /* Call the host backend to capture the audio input data. */ 741 uint32_t cSamplesCaptured; 742 rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured); 743 if (RT_FAILURE(rc)) 744 break; 745 746 //cbData = AUDIOMIXBUF_S2B(&pStream->MixBuf, AudioMixBufMixed(&pStream->MixBuf))); 747 748 } 749 else /* PDMAUDIODIR_OUT */ 750 { 751 uint32_t cSamplesMixed = 0; 593 uint32_t cSamplesToCapture = AudioMixBufFree(&pGstStream->MixBuf); 594 if (cSamplesToCapture) 595 { 596 if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE) 597 { 598 uint32_t cSamplesCaptured = 0; 599 600 /* Call the host backend to capture the audio input data. */ 601 rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured); 602 if (RT_FAILURE(rc)) 603 break; 604 605 LogFlowFunc(("%s: %RU32 samples captured, rc=%Rrc\n", pHstStream->szName, cSamplesCaptured, rc)); 606 } 607 } 608 } 609 else if (pHstStream->enmDir == PDMAUDIODIR_OUT) 610 { 752 611 uint32_t cSamplesToMix = AudioMixBufUsed(&pGstStream->MixBuf); 753 612 … … 757 616 if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE) 758 617 { 759 /* int rc2 = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);760 if (RT_SUCCESS(rc))761 rc = rc2;762 }*/763 764 618 rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cSamplesToMix, &cSamplesMixed); 765 619 766 LogFlowFunc(("%s: %RU32/%RU32 samples mixed, rc=%Rrc\n",620 LogFlowFunc(("%s: %RU32/%RU32 playback samples mixed, rc=%Rrc\n", 767 621 pHstStream->szName, cSamplesMixed, cSamplesToMix, rc)); 768 622 } 769 623 } 770 624 } 625 else 626 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 771 627 772 628 if (RT_SUCCESS(rc)) … … 775 631 } while (0); 776 632 633 if (RT_FAILURE(rc)) 634 LogFunc(("Failed with %Rrc\n", rc)); 635 777 636 return rc; 778 637 } 779 #else 780 static DECLCALLBACK(int) drvAudioGetDataIn(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbAvailIn) 781 { 782 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 783 /* pcbAvailIn is optional. */ 784 785 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 786 787 int rc = RTCritSectEnter(&pThis->CritSect); 788 if (RT_FAILURE(rc)) 789 return rc; 790 791 uint32_t cbAvailIn = 0; 792 793 PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL; 794 while ((pHstStrmIn = drvAudioFindAnyHstIn(pThis, pHstStrmIn))) 795 { 796 /* Disabled? Skip it! */ 797 if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)) 798 continue; 799 800 /* Call the host backend to capture the audio input data. */ 801 uint32_t cSamplesCaptured; 802 int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn, 803 &cSamplesCaptured); 804 if (RT_FAILURE(rc2)) 805 continue; 806 807 PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn; 808 AssertPtrBreak(pGstStrmIn); 809 810 if (pGstStrmIn->State.fActive) 811 { 812 cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, 813 AudioMixBufMixed(&pHstStrmIn->MixBuf))); 814 #ifdef DEBUG_andy 815 LogFlowFunc(("\t[%s] cbAvailIn=%RU32\n", pHstStrmIn->MixBuf.pszName, cbAvailIn)); 816 #endif 817 } 818 } 819 820 if (RT_SUCCESS(rc)) 821 { 822 if (pcbAvailIn) 823 *pcbAvailIn = cbAvailIn; 824 } 825 826 int rc2 = RTCritSectLeave(&pThis->CritSect); 827 if (RT_SUCCESS(rc)) 828 rc = rc2; 829 830 if (RT_FAILURE(rc)) 831 LogFlowFuncLeaveRC(rc); 832 833 return rc; 834 } 835 836 static DECLCALLBACK(int) drvAudioGetDataOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbFreeOut, uint32_t *pcSamplesLive) 837 { 838 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 839 /* pcbFreeOut is optional. */ 840 /* pcSamplesLive is optional. */ 841 842 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 843 844 int rc = RTCritSectEnter(&pThis->CritSect); 845 if (RT_FAILURE(rc)) 846 return rc; 847 848 static uint64_t s_tsLast = 0; 849 850 851 uint64_t s_tsDelta = RTTimeNanoTS() - s_tsLast; 852 LogFlowFunc(("delta=%RU64 (%RU64ms) -> ", s_tsDelta, s_tsDelta / 1000 / 1000)); 853 854 #if 0 855 PPDMAUDIOHSTSTRMOUT pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, NULL); 856 uint64_t ns = s_tsDelta / pHstStrmOut->Props.uHz; 857 858 859 860 uint32_t cSamplesMin = (cTicksElapsed / pSink->PCMProps.uHz) * pSink->PCMProps.cChannels; 861 #endif 862 863 s_tsLast = RTTimeNanoTS(); 864 865 /* 866 * Playback. 867 */ 868 uint32_t cSamplesLive = 0; 869 uint32_t cbFreeOut = UINT32_MAX; 870 871 PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL; 872 while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut))) 873 { 874 cSamplesLive = AudioMixBufAvail(&pHstStrmOut->MixBuf); 875 876 /* Has this stream marked as disabled but there still were guest streams relying 877 * on it? Check if this stream now can be closed and do so, if possible. */ 878 if ( (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE) 879 && !cSamplesLive) 880 { 881 /* Stop playing the current (pending) stream. */ 882 int rc2 = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE); 883 if (RT_SUCCESS(rc2)) 884 { 885 pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE; 886 887 LogFunc(("[%s] Disabling stream\n", pHstStrmOut->MixBuf.pszName)); 888 } 889 else 890 LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc2)); 891 892 continue; 893 } 894 895 LogFlowFunc(("[%s] cSamplesLive=%RU32\n", pHstStrmOut->MixBuf.pszName, cSamplesLive)); 896 897 /* 898 * No live samples to play at the moment? 899 * 900 * Tell the device emulation for each connected guest stream how many 901 * bytes are free so that the device emulation can continue writing data to 902 * these streams. 903 */ 904 PPDMAUDIOGSTSTRMOUT pGstStrmOut; 905 uint32_t cbFree2 = UINT32_MAX; 906 RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node) 907 { 908 if (pGstStrmOut->State.fActive) 909 { 910 /* Tell the sound device emulation how many samples are free 911 * so that it can start writing PCM data to us. */ 912 cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf, 913 AudioMixBufFree(&pGstStrmOut->MixBuf))); 914 #ifdef DEBUG_andy 915 LogFlowFunc(("\t[%s] cbFreeOut=%RU32\n", pGstStrmOut->MixBuf.pszName, cbFree2)); 916 #endif 917 } 918 } 919 920 cbFreeOut = RT_MIN(cbFreeOut, cbFree2); 921 } 922 923 if (RT_SUCCESS(rc)) 924 { 925 if (cbFreeOut == UINT32_MAX) 926 cbFreeOut = 0; 927 928 if (pcbFreeOut) 929 *pcbFreeOut = cbFreeOut; 930 931 if (pcSamplesLive) 932 *pcSamplesLive = cSamplesLive; 933 } 934 935 int rc2 = RTCritSectLeave(&pThis->CritSect); 936 if (RT_SUCCESS(rc)) 937 rc = rc2; 938 939 if (RT_FAILURE(rc)) 940 LogFlowFuncLeaveRC(rc); 941 942 return rc; 943 } 944 #endif 945 946 #if 1 947 static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed) 638 639 static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, 640 uint32_t *pcSamplesPlayed) 948 641 { 949 642 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); … … 951 644 /* pcSamplesPlayed is optional. */ 952 645 646 AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT, 647 ("Stream '%s' is not an output stream and therefore cannot be played back (direction is 0x%x)\n", 648 pStream->szName, pStream->enmDir)); 649 953 650 AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED, 954 651 ("Unable to play stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus)); … … 981 678 982 679 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream); 680 AssertPtr(pHstStream); 983 681 PPDMAUDIOSTREAM pGstStream = pHstStream->pPair; 984 682 AssertPtr(pGstStream); … … 1021 719 } 1022 720 } 1023 #if 0 1024 if (pStream->pPair) 1025 { 1026 bool fIsEmpty = AudioMixBufIsEmpty(&pStream->pPair->MixBuf); 1027 1028 if ( !pPair->State.fActive 1029 && fIsEmpty) 1030 continue; 1031 1032 if () 1033 { 1034 pGstStrmOut->State.fEmpty = true; 1035 fNeedsCleanup |= !pGstStrmOut->State.fActive; 1036 } 1037 } 1038 1039 if (fNeedsCleanup) 1040 { 1041 RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node) 1042 { 1043 if (!pGstStrmOut->State.fActive) 1044 drvAudioDestroyGstOut(pThis, pGstStrmOut); 1045 } 1046 } 1047 #endif 721 1048 722 } while (0); 1049 723 … … 1063 737 return rc; 1064 738 } 1065 #else 1066 static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed) 1067 { 1068 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1069 /* pcSamplesPlayed is optional. */ 739 740 static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, 741 uint32_t *pcSamplesCaptured) 742 { 743 AssertMsg(pStream->enmDir == PDMAUDIODIR_IN, 744 ("Stream '%s' is not an input stream and therefore cannot be captured (direction is 0x%x)\n", 745 pStream->szName, pStream->enmDir)); 746 747 AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED, 748 ("Unable to capture stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus)); 1070 749 1071 750 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); … … 1075 754 return rc; 1076 755 1077 /* Backend output (temporarily) disabled / unavailable? */ 1078 if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT)) 1079 { 1080 rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg); 1081 AssertRC(rc); 1082 1083 if ( !pThis->BackendCfg.cSinks 1084 || !pThis->BackendCfg.cMaxStreamsOut) 1085 { 1086 int rc2 = RTCritSectLeave(&pThis->CritSect); 1087 AssertRC(rc2); 1088 1089 return VERR_NOT_AVAILABLE; 1090 } 1091 } 1092 1093 /* 1094 * Process all enabled host output streams. 1095 */ 1096 uint32_t cSamplesPlayedMax = 0; 1097 PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL; 1098 while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut))) 1099 { 1100 #if 0 1101 uint32_t cStreamsLive; 1102 uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive); 1103 if (!cStreamsLive) 1104 cSamplesLive = 0; 1105 1106 /* Has this stream marked as disabled but there still were guest streams relying 1107 * on it? Check if this stream now can be closed and do so, if possible. */ 1108 if ( pHstStrmOut->fPendingDisable 1109 && !cStreamsLive) 1110 { 1111 /* Stop playing the current (pending) stream. */ 1112 int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, 1113 PDMAUDIOSTREAMCMD_DISABLE); 1114 if (RT_SUCCESS(rc2)) 1115 { 1116 pHstStrmOut->fEnabled = false; 1117 pHstStrmOut->fPendingDisable = false; 1118 1119 LogFunc(("\t%p: Disabling stream\n", pHstStrmOut)); 1120 } 1121 else 1122 LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n", 1123 pHstStrmOut, rc2)); 1124 1125 continue; 1126 } 1127 #endif 1128 uint32_t cSamplesPlayed = 0; 1129 int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed); 1130 if (RT_FAILURE(rc2)) 1131 { 1132 int rc3 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE); 1133 AssertRC(rc3); 1134 } 1135 else 1136 cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax); 1137 1138 LogFlowFunc(("\t[%s] cSamplesPlayed=%RU32, cSamplesPlayedMax=%RU32, rc=%Rrc\n", 1139 pHstStrmOut->MixBuf.pszName, cSamplesPlayed, cSamplesPlayedMax, rc2)); 1140 1141 bool fNeedsCleanup = false; 1142 1143 PPDMAUDIOGSTSTRMOUT pGstStrmOut; 1144 RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node) 1145 { 1146 if ( !pGstStrmOut->State.fActive 1147 && pGstStrmOut->State.fEmpty) 1148 continue; 1149 1150 if (AudioMixBufIsEmpty(&pGstStrmOut->MixBuf)) 1151 { 1152 pGstStrmOut->State.fEmpty = true; 1153 fNeedsCleanup |= !pGstStrmOut->State.fActive; 1154 } 1155 } 1156 1157 if (fNeedsCleanup) 1158 { 1159 RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node) 1160 { 1161 if (!pGstStrmOut->State.fActive) 1162 drvAudioDestroyGstOut(pThis, pGstStrmOut); 1163 } 1164 } 1165 } 1166 1167 if (RT_SUCCESS(rc)) 1168 { 1169 if (pcSamplesPlayed) 1170 *pcSamplesPlayed = cSamplesPlayedMax; 756 LogFlowFunc(("[%s]\n", pStream->szName)); 757 758 uint32_t cSamplesCaptured = 0; 759 760 do 761 { 762 /* Backend input (temporarily) disabled / unavailable? */ 763 if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING) 764 { 765 rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg); 766 AssertRC(rc); 767 768 if ( !pThis->BackendCfg.cSources 769 || !pThis->BackendCfg.cMaxStreamsIn) 770 { 771 rc = VERR_NOT_AVAILABLE; 772 break; 773 } 774 } 775 776 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream); 777 AssertPtr(pHstStream); 778 PPDMAUDIOSTREAM pGstStream = pHstStream->pPair; 779 AssertPtr(pGstStream); 780 781 uint32_t cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf); 782 if (cSamplesLive) 783 { 784 PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream); 785 if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE) 786 { 787 rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured); 788 if (RT_FAILURE(rc)) 789 drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE); 790 } 791 792 LogFlowFunc(("[%s] strmSts=0x%x, cSamplesCaptured=%RU32, rc=%Rrc\n", pStream->szName, strmSts, cSamplesCaptured, rc)); 793 794 if (RT_SUCCESS(rc)) 795 { 796 rc = drvAudioStreamIterateInternal(pThis, pStream); 797 if (RT_SUCCESS(rc)) 798 cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf); 799 } 800 } 801 802 if (!cSamplesLive) 803 { 804 /* Has the host stream marked as disabled but there still were guest streams relying 805 * on it? Check if the stream now can be closed and do so, if possible. */ 806 if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE) 807 { 808 LogFunc(("%s: Closing pending stream\n", pHstStream->szName)); 809 rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE); 810 if (RT_SUCCESS(rc)) 811 { 812 pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE; 813 } 814 else 815 LogFunc(("%s: Backend vetoed against closing input stream, rc=%Rrc\n", pHstStream->szName, rc)); 816 } 817 } 818 819 } while (0); 820 821 if (RT_SUCCESS(rc)) 822 { 823 if (pcSamplesCaptured) 824 *pcSamplesCaptured = cSamplesCaptured; 1171 825 } 1172 826 … … 1180 834 return rc; 1181 835 } 1182 #endif1183 836 1184 837 #ifdef VBOX_WITH_AUDIO_CALLBACKS … … 1378 1031 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO); 1379 1032 LogFlowFunc(("pThis=%p, pDrvIns=%p\n", pThis, pDrvIns)); 1033 1034 int rc = RTCritSectInit(&pThis->CritSect); 1035 1036 /** @todo Add audio driver options. */ 1037 1038 /* 1039 * If everything went well, initialize the lower driver. 1040 */ 1041 if (RT_SUCCESS(rc)) 1042 rc = drvAudioHostInit(pCfgHandle, pThis); 1043 1044 LogFlowFuncLeaveRC(rc); 1045 return rc; 1046 } 1047 1048 static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, 1049 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 1050 { 1051 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1052 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1053 1054 if (!pStream) 1055 { 1056 if (pcbRead) 1057 *pcbRead = 0; 1058 return VINF_SUCCESS; 1059 } 1060 1061 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 1062 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 1063 /* pcbWritten is optional. */ 1064 1065 int rc = RTCritSectEnter(&pThis->CritSect); 1066 if (RT_FAILURE(rc)) 1067 return rc; 1068 1069 AssertMsg(pStream->enmDir == PDMAUDIODIR_IN, 1070 ("Stream '%s' is not an input stream and therefore cannot be read from (direction is 0x%x)\n", 1071 pStream->szName, pStream->enmDir)); 1072 1073 if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING) 1074 { 1075 if (pcbRead) 1076 *pcbRead = 0; 1077 1078 return RTCritSectLeave(&pThis->CritSect); 1079 } 1080 1081 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream); 1082 PPDMAUDIOSTREAM pGstStream = pHstStream->pPair; 1083 1084 AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED, 1085 ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName)); 1086 1087 Log3Func(("%s\n", pStream->szName)); 1088 1089 /* 1090 * Read from the parent buffer (that is, the guest buffer) which 1091 * should have the audio data in the format the guest needs. 1092 */ 1093 uint32_t cRead; 1094 rc = AudioMixBufReadCirc(&pGstStream->MixBuf, pvBuf, cbBuf, &cRead); 1095 if (RT_SUCCESS(rc)) 1096 { 1097 if (cRead) 1098 AudioMixBufFinish(&pGstStream->MixBuf, cRead); 1099 1100 if (pcbRead) 1101 *pcbRead = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead); 1102 } 1103 1104 LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n", 1105 cRead, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead), rc)); 1106 1107 int rc2 = RTCritSectLeave(&pThis->CritSect); 1108 if (RT_SUCCESS(rc)) 1109 rc = rc2; 1110 1111 return rc; 1112 } 1113 1114 static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface, 1115 PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest, 1116 PPDMAUDIOSTREAM *ppStream) 1117 { 1118 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1119 AssertPtrReturn(pCfgHost, VERR_INVALID_POINTER); 1120 AssertPtrReturn(pCfgGuest, VERR_INVALID_POINTER); 1121 AssertPtrReturn(ppStream, VERR_INVALID_POINTER); 1122 1123 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1124 1125 int rc = RTCritSectEnter(&pThis->CritSect); 1126 if (RT_FAILURE(rc)) 1127 return rc; 1128 1129 LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName)); 1130 #ifdef DEBUG 1131 DrvAudioHlpStreamCfgPrint(pCfgHost); 1132 DrvAudioHlpStreamCfgPrint(pCfgGuest); 1133 #endif 1134 1135 /* 1136 * The guest stream always will get the audio stream configuration told 1137 * by the device emulation (which in turn was/could be set by the guest OS). 1138 */ 1139 PPDMAUDIOSTREAM pGstStrm = NULL; 1140 1141 /** @todo Docs! */ 1142 PPDMAUDIOSTREAM pHstStrm = NULL; 1143 1144 #define RC_BREAK(x) { rc = x; break; } 1145 1146 do 1147 { 1148 if ( !DrvAudioHlpStreamCfgIsValid(pCfgHost) 1149 || !DrvAudioHlpStreamCfgIsValid(pCfgGuest)) 1150 { 1151 RC_BREAK(VERR_INVALID_PARAMETER); 1152 } 1153 1154 /* Make sure that both configurations actually intend the same thing. */ 1155 if (pCfgHost->enmDir != pCfgGuest->enmDir) 1156 { 1157 AssertMsgFailed(("Stream configuration directions do not match\n")); 1158 RC_BREAK(VERR_INVALID_PARAMETER); 1159 } 1160 1161 /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data 1162 * which the host backend will need. */ 1163 size_t cbHstStrm; 1164 if (pCfgHost->enmDir == PDMAUDIODIR_IN) 1165 { 1166 if (!pThis->cStreamsFreeIn) 1167 { 1168 LogFlowFunc(("No more input streams free to use, bailing out\n")); 1169 RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS); 1170 } 1171 1172 /* Validate backend configuration. */ 1173 if (!pThis->BackendCfg.cbStreamIn) 1174 { 1175 LogFlowFunc(("Backend input configuration not valid, bailing out\n")); 1176 RC_BREAK(VERR_INVALID_PARAMETER); 1177 } 1178 1179 cbHstStrm = pThis->BackendCfg.cbStreamIn; 1180 } 1181 else /* Out */ 1182 { 1183 if (!pThis->cStreamsFreeOut) 1184 { 1185 LogFlowFunc(("Maximum number of host output streams reached\n")); 1186 RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS); 1187 } 1188 1189 /* Validate backend configuration. */ 1190 if (!pThis->BackendCfg.cbStreamOut) 1191 { 1192 LogFlowFunc(("Backend output configuration invalid, bailing out\n")); 1193 RC_BREAK(VERR_INVALID_PARAMETER); 1194 } 1195 1196 cbHstStrm = pThis->BackendCfg.cbStreamOut; 1197 } 1198 1199 pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm); 1200 AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY); 1201 1202 pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST; 1203 pHstStrm->enmDir = pCfgHost->enmDir; 1204 1205 pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM)); 1206 AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY); 1207 1208 pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST; 1209 pGstStrm->enmDir = pCfgGuest->enmDir; 1210 1211 /* 1212 * Create host stream. 1213 */ 1214 1215 RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)", 1216 strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>"); 1217 1218 /* Note: Direction is always from child -> parent. */ 1219 uint32_t cSamples = 0; 1220 rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStrm, pCfgHost, &cSamples); 1221 if (RT_FAILURE(rc)) 1222 { 1223 LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc)); 1224 break; 1225 } 1226 1227 pHstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED; 1228 pHstStrm->pPair = pGstStrm; 1229 1230 rc = DrvAudioHlpStreamCfgToProps(pCfgHost, &pHstStrm->Props); 1231 AssertRCBreak(rc); 1232 1233 rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4); 1234 AssertRCBreak(rc); 1235 1236 /* 1237 * Create guest stream. 1238 */ 1239 1240 RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)", 1241 strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>"); 1242 1243 rc = DrvAudioHlpStreamCfgToProps(pCfgGuest, &pGstStrm->Props); 1244 AssertRCBreak(rc); 1245 1246 rc = AudioMixBufInit(&pGstStrm->MixBuf, pGstStrm->szName, &pGstStrm->Props, cSamples * 2); 1247 if (RT_SUCCESS(rc)) 1248 { 1249 if (pCfgGuest->enmDir == PDMAUDIODIR_IN) 1250 { 1251 /* Host (Parent) -> Guest (Child). */ 1252 rc = AudioMixBufLinkTo(&pHstStrm->MixBuf, &pGstStrm->MixBuf); 1253 } 1254 else 1255 { 1256 /* Guest (Parent) -> Host (Child). */ 1257 rc = AudioMixBufLinkTo(&pGstStrm->MixBuf, &pHstStrm->MixBuf); 1258 } 1259 } 1260 1261 pGstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED; 1262 pGstStrm->pPair = pHstStrm; 1263 1264 AssertRCBreak(rc); 1265 1266 } while (0); 1267 1268 #undef RC_BREAK 1269 1270 if (RT_FAILURE(rc)) 1271 { 1272 drvAudioStreamDestroyInternal(pThis, pGstStrm); 1273 pGstStrm = NULL; 1274 1275 drvAudioStreamDestroyInternal(pThis, pHstStrm); 1276 pHstStrm = NULL; 1277 } 1278 else 1279 { 1280 /* Set initial reference counts. */ 1281 RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node); 1282 pGstStrm->cRefs = 1; 1283 1284 RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node); 1285 pHstStrm->cRefs = 1; 1286 1287 if (pCfgHost->enmDir == PDMAUDIODIR_IN) 1288 { 1289 Assert(pThis->cStreamsFreeIn); 1290 pThis->cStreamsFreeIn--; 1291 } 1292 else /* Out */ 1293 { 1294 Assert(pThis->cStreamsFreeOut); 1295 pThis->cStreamsFreeOut--; 1296 } 1297 1298 /* Always return the guest-side part to the device emulation. */ 1299 *ppStream = pGstStrm; 1300 } 1301 1302 int rc2 = RTCritSectLeave(&pThis->CritSect); 1303 if (RT_SUCCESS(rc)) 1304 rc = rc2; 1305 1306 LogFlowFuncLeaveRC(rc); 1307 return rc; 1308 } 1309 1310 #if 1 1311 static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg) 1312 { 1313 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1314 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 1315 1316 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1317 1318 int rc = RTCritSectEnter(&pThis->CritSect); 1319 if (RT_FAILURE(rc)) 1320 return rc; 1321 1322 rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg); 1323 1324 int rc2 = RTCritSectLeave(&pThis->CritSect); 1325 if (RT_SUCCESS(rc)) 1326 rc = rc2; 1327 1328 LogFlowFuncLeaveRC(rc); 1329 return rc; 1330 } 1331 1332 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioGetStatus(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir) 1333 { 1334 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN); 1335 1336 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1337 1338 int rc = RTCritSectEnter(&pThis->CritSect); 1339 if (RT_FAILURE(rc)) 1340 return PDMAUDIOBACKENDSTS_UNKNOWN; 1341 1342 PDMAUDIOBACKENDSTS backendSts = pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, enmDir); 1343 1344 int rc2 = RTCritSectLeave(&pThis->CritSect); 1345 if (RT_SUCCESS(rc)) 1346 rc = rc2; 1347 1348 LogFlowFuncLeaveRC(rc); 1349 return backendSts; 1350 } 1351 1352 static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioStreamGetStatus(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 1353 { 1354 AssertPtrReturn(pInterface, false); 1355 1356 if (!pStream) 1357 return PDMAUDIOSTRMSTS_FLAG_NONE; 1358 1359 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1360 1361 int rc2 = RTCritSectEnter(&pThis->CritSect); 1362 AssertRC(rc2); 1363 1364 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream); 1365 PDMAUDIOSTRMSTS strmSts = pHstStream->fStatus; 1366 1367 LogFlowFunc(("%s: strmSts=0x%x\n", pHstStream->szName, strmSts)); 1368 rc2 = RTCritSectLeave(&pThis->CritSect); 1369 AssertRC(rc2); 1370 1371 return strmSts; 1372 } 1373 1374 static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol) 1375 { 1376 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1377 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1378 AssertPtrReturn(pVol, VERR_INVALID_POINTER); 1379 1380 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1381 1382 LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted)); 1383 1384 AudioMixBufSetVolume(&pStream->MixBuf, pVol); 1385 1386 return VINF_SUCCESS; 1387 } 1388 #endif 1389 1390 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 1391 { 1392 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1393 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1394 1395 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface); 1396 1397 int rc = RTCritSectEnter(&pThis->CritSect); 1398 AssertRC(rc); 1399 1400 PDMAUDIODIR enmDir = pStream->enmDir; 1401 1402 LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs)); 1403 if (pStream->cRefs > 1) 1404 rc = VERR_WRONG_ORDER; 1405 1406 if (RT_SUCCESS(rc)) 1407 { 1408 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream); 1409 PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream; 1410 1411 LogFlowFunc(("\tHost : %s\n", pHstStream ? pHstStream->szName : "<None>")); 1412 LogFlowFunc(("\tGuest: %s\n", pGstStream ? pGstStream->szName : "<None>")); 1413 1414 /* Should prevent double frees. */ 1415 Assert(pHstStream != pGstStream); 1416 1417 if (pHstStream) 1418 { 1419 pHstStream->pPair = NULL; 1420 RTListNodeRemove(&pHstStream->Node); 1421 } 1422 1423 if (pGstStream) 1424 { 1425 pGstStream->pPair = NULL; 1426 RTListNodeRemove(&pGstStream->Node); 1427 } 1428 1429 if (pHstStream) 1430 { 1431 rc = drvAudioStreamDestroyInternal(pThis, pHstStream); 1432 AssertRC(rc); 1433 1434 pHstStream = NULL; 1435 } 1436 1437 if (pGstStream) 1438 { 1439 rc = drvAudioStreamDestroyInternal(pThis, pGstStream); 1440 AssertRC(rc); 1441 1442 pGstStream = NULL; 1443 } 1444 } 1445 1446 if (RT_SUCCESS(rc)) 1447 { 1448 if (enmDir == PDMAUDIODIR_IN) 1449 { 1450 pThis->cStreamsFreeIn++; 1451 } 1452 else /* Out */ 1453 { 1454 pThis->cStreamsFreeOut++; 1455 } 1456 } 1457 1458 int rc2 = RTCritSectLeave(&pThis->CritSect); 1459 if (RT_SUCCESS(rc)) 1460 rc = rc2; 1461 1462 LogFlowFuncLeaveRC(rc); 1463 return rc; 1464 } 1465 1466 static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream) 1467 { 1468 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1469 AssertPtrReturn(pHstStream, VERR_INVALID_POINTER); 1470 1471 AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST, 1472 ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName)); 1473 1474 int rc = VINF_SUCCESS; 1475 1476 LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus)); 1477 1478 if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED) 1479 { 1480 if (pThis->pHostDrvAudio) 1481 rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream); 1482 if (RT_SUCCESS(rc)) 1483 pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED; 1484 } 1485 1486 LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc)); 1487 return rc; 1488 } 1489 1490 static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream) 1491 { 1492 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1493 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1494 1495 LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs)); 1496 1497 if (pStream->cRefs > 1) 1498 return VERR_WRONG_ORDER; 1499 1500 int rc = VINF_SUCCESS; 1501 1502 if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST) 1503 { 1504 if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED) 1505 { 1506 rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE); 1507 if (RT_SUCCESS(rc)) 1508 pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED; 1509 } 1510 } 1511 else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST) 1512 { 1513 rc = drvAudioStreamDestroyInternalBackend(pThis, pStream); 1514 } 1515 else 1516 AssertFailedReturn(VERR_NOT_IMPLEMENTED); 1517 1518 if (RT_SUCCESS(rc)) 1519 { 1520 /* Destroy mixing buffer. */ 1521 AudioMixBufDestroy(&pStream->MixBuf); 1522 1523 if (pStream) 1524 { 1525 RTMemFree(pStream); 1526 pStream = NULL; 1527 } 1528 } 1529 1530 LogFlowFunc(("Returning %Rrc\n", rc)); 1531 return rc; 1532 } 1533 1534 /********************************************************************/ 1535 1536 /** 1537 * @interface_method_impl{PDMIBASE,pfnQueryInterface} 1538 */ 1539 static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID) 1540 { 1541 LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID)); 1542 1543 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); 1544 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO); 1545 1546 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); 1547 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector); 1548 1549 return NULL; 1550 } 1551 1552 /** 1553 * Power Off notification. 1554 * 1555 * @param pDrvIns The driver instance data. 1556 */ 1557 static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns) 1558 { 1559 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO); 1560 1561 LogFlowFuncEnter(); 1562 1563 /* Just destroy the host stream on the backend side. 1564 * The rest will either be destructed by the device emulation or 1565 * in drvAudioDestruct(). */ 1566 PPDMAUDIOSTREAM pStream; 1567 RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node) 1568 drvAudioStreamDestroyInternalBackend(pThis, pStream); 1569 1570 /* 1571 * Last call for the driver below us. 1572 * Let it know that we reached end of life. 1573 */ 1574 if (pThis->pHostDrvAudio->pfnShutdown) 1575 pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio); 1576 1577 pThis->pHostDrvAudio = NULL; 1578 1579 LogFlowFuncLeave(); 1580 } 1581 1582 /** 1583 * Constructs an audio driver instance. 1584 * 1585 * @copydoc FNPDMDRVCONSTRUCT 1586 */ 1587 static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags) 1588 { 1589 LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags)); 1590 1591 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO); 1592 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); 1380 1593 1381 1594 RTListInit(&pThis->lstHstStreams); … … 1385 1598 RTListInit(&pThis->lstCBOut); 1386 1599 #endif 1387 1388 int rc = RTCritSectInit(&pThis->CritSect);1389 1390 /** @todo Add audio driver options. */1391 1392 /*1393 * If everything went well, initialize the lower driver.1394 */1395 if (RT_SUCCESS(rc))1396 rc = drvAudioHostInit(pCfgHandle, pThis);1397 1398 LogFlowFuncLeaveRC(rc);1399 return rc;1400 }1401 1402 #if 11403 static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,1404 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)1405 {1406 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1407 AssertPtrReturn(pThis, VERR_INVALID_POINTER);1408 1409 if (!pStream)1410 {1411 if (pcbRead)1412 *pcbRead = 0;1413 return VINF_SUCCESS;1414 }1415 1416 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);1417 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);1418 /* pcbWritten is optional. */1419 1420 int rc = RTCritSectEnter(&pThis->CritSect);1421 if (RT_FAILURE(rc))1422 return rc;1423 1424 if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)1425 {1426 if (pcbRead)1427 *pcbRead = 0;1428 1429 return RTCritSectLeave(&pThis->CritSect);1430 }1431 1432 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);1433 1434 AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,1435 ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName));1436 1437 /*1438 * Read from the parent buffer (that is, the guest buffer) which1439 * should have the audio data in the format the guest needs.1440 */1441 uint32_t cRead;1442 rc = AudioMixBufReadCirc(&pStream->MixBuf, pvBuf, cbBuf, &cRead);1443 if (RT_SUCCESS(rc))1444 {1445 AudioMixBufFinish(&pStream->MixBuf, cRead);1446 1447 if (pcbRead)1448 *pcbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);1449 }1450 1451 LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",1452 cRead, AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead), rc));1453 1454 int rc2 = RTCritSectLeave(&pThis->CritSect);1455 if (RT_SUCCESS(rc))1456 rc = rc2;1457 1458 return rc;1459 }1460 #else1461 static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn,1462 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)1463 {1464 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1465 AssertPtrReturn(pThis, VERR_INVALID_POINTER);1466 1467 if (!pGstStrmIn)1468 return VERR_NOT_AVAILABLE;1469 1470 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);1471 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);1472 /* pcbWritten is optional. */1473 1474 int rc = RTCritSectEnter(&pThis->CritSect);1475 if (RT_FAILURE(rc))1476 return rc;1477 1478 if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_IN))1479 {1480 if (pcbRead)1481 *pcbRead = 0;1482 1483 return RTCritSectLeave(&pThis->CritSect);1484 }1485 1486 PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;1487 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);1488 1489 AssertMsg(pGstStrmIn->pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,1490 ("Reading from disabled host input stream \"%s\" not possible\n", pGstStrmIn->MixBuf.pszName));1491 1492 /*1493 * Read from the parent buffer (that is, the guest buffer) which1494 * should have the audio data in the format the guest needs.1495 */1496 uint32_t cRead;1497 rc = AudioMixBufReadCirc(&pGstStrmIn->MixBuf, pvBuf, cbBuf, &cRead);1498 if (RT_SUCCESS(rc))1499 {1500 AudioMixBufFinish(&pGstStrmIn->MixBuf, cRead);1501 1502 if (pcbRead)1503 *pcbRead = AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead);1504 }1505 1506 LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",1507 cRead, AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead), rc));1508 1509 int rc2 = RTCritSectLeave(&pThis->CritSect);1510 if (RT_SUCCESS(rc))1511 rc = rc2;1512 1513 return rc;1514 }1515 #endif1516 1517 #if 01518 static DECLCALLBACK(int) drvAudioEnableOut(PPDMIAUDIOCONNECTOR pInterface,1519 PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable)1520 {1521 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1522 1523 if (!pGstStrmOut)1524 return VERR_NOT_AVAILABLE;1525 1526 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1527 1528 int rc = VINF_SUCCESS;1529 1530 PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;1531 AssertPtr(pHstStrmOut);1532 1533 if (fEnable)1534 {1535 /* Is a pending disable outstanding? Then disable first. */1536 if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)1537 {1538 rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);1539 if (RT_SUCCESS(rc))1540 pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;1541 }1542 1543 if (RT_SUCCESS(rc))1544 rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);1545 1546 if (RT_SUCCESS(rc))1547 pGstStrmOut->State.fActive = fEnable;1548 }1549 else /* Disable */1550 {1551 if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)1552 {1553 size_t cGstStrmsActive = 0;1554 1555 /*1556 * Check if there are any active guest streams assigned1557 * to this host stream which still are being marked as active.1558 *1559 * In that case we have to defer closing the host stream and1560 * wait until all guest streams have been finished.1561 */1562 PPDMAUDIOGSTSTRMOUT pIter;1563 RTListForEach(&pHstStrmOut->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)1564 {1565 if (pIter->State.fActive)1566 {1567 cGstStrmsActive++;1568 break; /* At least one assigned & active guest stream is enough. */1569 }1570 }1571 1572 /* Do we need to defer closing the host stream? */1573 if (cGstStrmsActive)1574 {1575 LogFlowFunc(("Closing stream deferred: %zu guest stream(s) active\n", cGstStrmsActive));1576 pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;1577 1578 rc = VERR_AUDIO_STREAM_PENDING_DISABLE;1579 }1580 else1581 {1582 rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);1583 if (RT_SUCCESS(rc))1584 pGstStrmOut->State.fActive = fEnable;1585 }1586 }1587 }1588 1589 LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",1590 pGstStrmOut->MixBuf.pszName, fEnable, pHstStrmOut->fStatus, rc));1591 1592 return rc;1593 }1594 #endif1595 1596 static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,1597 PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest,1598 PPDMAUDIOSTREAM *ppStream)1599 {1600 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1601 AssertPtrReturn(pCfgHost, VERR_INVALID_POINTER);1602 AssertPtrReturn(pCfgGuest, VERR_INVALID_POINTER);1603 AssertPtrReturn(ppStream, VERR_INVALID_POINTER);1604 1605 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1606 1607 int rc = RTCritSectEnter(&pThis->CritSect);1608 if (RT_FAILURE(rc))1609 return rc;1610 1611 LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));1612 #ifdef DEBUG1613 DrvAudioHlpStreamCfgPrint(pCfgHost);1614 DrvAudioHlpStreamCfgPrint(pCfgGuest);1615 #endif1616 1617 /*1618 * The guest stream always will get the audio stream configuration told1619 * by the device emulation (which in turn was/could be set by the guest OS).1620 */1621 PPDMAUDIOSTREAM pGstStrm = NULL;1622 1623 /** @todo Docs! */1624 PPDMAUDIOSTREAM pHstStrm = NULL;1625 1626 #define RC_BREAK(x) { rc = x; break; }1627 1628 do1629 {1630 if ( !DrvAudioHlpStreamCfgIsValid(pCfgHost)1631 || !DrvAudioHlpStreamCfgIsValid(pCfgGuest))1632 {1633 RC_BREAK(VERR_INVALID_PARAMETER);1634 }1635 1636 /* Make sure that both configurations actually intend the same thing. */1637 if (pCfgHost->enmDir != pCfgGuest->enmDir)1638 {1639 AssertMsgFailed(("Stream configuration directions do not match\n"));1640 RC_BREAK(VERR_INVALID_PARAMETER);1641 }1642 1643 /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data1644 * which the host backend will need. */1645 size_t cbHstStrm;1646 if (pCfgHost->enmDir == PDMAUDIODIR_IN)1647 {1648 if (!pThis->cStreamsFreeIn)1649 {1650 LogFlowFunc(("No more input streams free to use, bailing out\n"));1651 RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS);1652 }1653 1654 /* Validate backend configuration. */1655 if (!pThis->BackendCfg.cbStreamIn)1656 {1657 LogFlowFunc(("Backend input configuration not valid, bailing out\n"));1658 RC_BREAK(VERR_INVALID_PARAMETER);1659 }1660 1661 cbHstStrm = pThis->BackendCfg.cbStreamIn;1662 }1663 else /* Out */1664 {1665 if (!pThis->cStreamsFreeOut)1666 {1667 LogFlowFunc(("Maximum number of host output streams reached\n"));1668 RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);1669 }1670 1671 /* Validate backend configuration. */1672 if (!pThis->BackendCfg.cbStreamOut)1673 {1674 LogFlowFunc(("Backend output configuration invalid, bailing out\n"));1675 RC_BREAK(VERR_INVALID_PARAMETER);1676 }1677 1678 cbHstStrm = pThis->BackendCfg.cbStreamOut;1679 }1680 1681 pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm);1682 AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY);1683 1684 pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST;1685 pHstStrm->enmDir = pCfgHost->enmDir;1686 1687 RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node);1688 1689 pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM));1690 AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY);1691 1692 pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST;1693 pGstStrm->enmDir = pCfgGuest->enmDir;1694 1695 RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node);1696 1697 /*1698 * Create host stream.1699 */1700 1701 RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)",1702 strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");1703 1704 /* Note: Direction is always from child -> parent. */1705 uint32_t cSamples = 0;1706 rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStrm, pCfgHost, &cSamples);1707 if (RT_FAILURE(rc))1708 {1709 LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));1710 break;1711 }1712 1713 pHstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;1714 pHstStrm->pPair = pGstStrm;1715 1716 rc = DrvAudioHlpStreamCfgToProps(pCfgHost, &pHstStrm->Props);1717 AssertRCBreak(rc);1718 1719 rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4);1720 AssertRCBreak(rc);1721 1722 /*1723 * Create guest stream.1724 */1725 1726 RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)",1727 strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>");1728 1729 rc = DrvAudioHlpStreamCfgToProps(pCfgGuest, &pGstStrm->Props);1730 AssertRCBreak(rc);1731 1732 rc = AudioMixBufInit(&pGstStrm->MixBuf, pGstStrm->szName, &pGstStrm->Props, cSamples * 2);1733 if (RT_SUCCESS(rc))1734 {1735 if (pCfgGuest->enmDir == PDMAUDIODIR_IN)1736 {1737 /* Host (Parent) -> Guest (Child). */1738 rc = AudioMixBufLinkTo(&pHstStrm->MixBuf, &pGstStrm->MixBuf);1739 }1740 else1741 {1742 /* Guest (Parent) -> Host (Child). */1743 rc = AudioMixBufLinkTo(&pGstStrm->MixBuf, &pHstStrm->MixBuf);1744 }1745 }1746 1747 pGstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;1748 pGstStrm->pPair = pHstStrm;1749 1750 AssertRCBreak(rc);1751 1752 } while (0);1753 1754 #undef RC_BREAK1755 1756 if (RT_FAILURE(rc))1757 {1758 drvAudioStreamDestroyInternal(pThis, pGstStrm);1759 pGstStrm = NULL;1760 1761 drvAudioStreamDestroyInternal(pThis, pHstStrm);1762 pHstStrm = NULL;1763 }1764 else1765 {1766 /* Set initial reference counts. */1767 pGstStrm->cRefs = 1;1768 pHstStrm->cRefs = 1;1769 1770 if (pCfgHost->enmDir == PDMAUDIODIR_IN)1771 {1772 Assert(pThis->cStreamsFreeIn);1773 pThis->cStreamsFreeIn--;1774 }1775 else /* Out */1776 {1777 Assert(pThis->cStreamsFreeOut);1778 pThis->cStreamsFreeOut--;1779 }1780 1781 /* Always return the guest-side part to the device emulation. */1782 *ppStream = pGstStrm;1783 }1784 1785 int rc2 = RTCritSectLeave(&pThis->CritSect);1786 if (RT_SUCCESS(rc))1787 rc = rc2;1788 1789 LogFlowFuncLeaveRC(rc);1790 return rc;1791 }1792 1793 #if 11794 static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)1795 {1796 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1797 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);1798 1799 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1800 1801 int rc = RTCritSectEnter(&pThis->CritSect);1802 if (RT_FAILURE(rc))1803 return rc;1804 1805 rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg);1806 1807 int rc2 = RTCritSectLeave(&pThis->CritSect);1808 if (RT_SUCCESS(rc))1809 rc = rc2;1810 1811 LogFlowFuncLeaveRC(rc);1812 return rc;1813 }1814 1815 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioGetStatus(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)1816 {1817 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);1818 1819 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1820 1821 int rc = RTCritSectEnter(&pThis->CritSect);1822 if (RT_FAILURE(rc))1823 return PDMAUDIOBACKENDSTS_UNKNOWN;1824 1825 PDMAUDIOBACKENDSTS backendSts = pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, enmDir);1826 1827 int rc2 = RTCritSectLeave(&pThis->CritSect);1828 if (RT_SUCCESS(rc))1829 rc = rc2;1830 1831 LogFlowFuncLeaveRC(rc);1832 return backendSts;1833 }1834 1835 static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioStreamGetStatus(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)1836 {1837 AssertPtrReturn(pInterface, false);1838 1839 if (!pStream)1840 return PDMAUDIOSTRMSTS_FLAG_NONE;1841 1842 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1843 1844 int rc2 = RTCritSectEnter(&pThis->CritSect);1845 AssertRC(rc2);1846 1847 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);1848 PDMAUDIOSTRMSTS strmSts = pHstStream->fStatus;1849 1850 LogFlowFunc(("%s: strmSts=0x%x\n", pHstStream->szName, strmSts));1851 rc2 = RTCritSectLeave(&pThis->CritSect);1852 AssertRC(rc2);1853 1854 return strmSts;1855 }1856 1857 static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)1858 {1859 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1860 AssertPtrReturn(pStream, VERR_INVALID_POINTER);1861 AssertPtrReturn(pVol, VERR_INVALID_POINTER);1862 1863 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1864 1865 LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));1866 1867 AudioMixBufSetVolume(&pStream->MixBuf, pVol);1868 1869 return VINF_SUCCESS;1870 }1871 #endif1872 1873 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)1874 {1875 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1876 AssertPtrReturn(pStream, VERR_INVALID_POINTER);1877 1878 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);1879 1880 int rc = RTCritSectEnter(&pThis->CritSect);1881 AssertRC(rc);1882 1883 PDMAUDIODIR enmDir = pStream->enmDir;1884 1885 LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));1886 if (pStream->cRefs > 1)1887 rc = VERR_WRONG_ORDER;1888 1889 if (RT_SUCCESS(rc))1890 {1891 PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);1892 PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;1893 1894 LogFlowFunc(("\tHost : %s\n", pHstStream ? pHstStream->szName : "<None>"));1895 LogFlowFunc(("\tGuest: %s\n", pGstStream ? pGstStream->szName : "<None>"));1896 1897 /* Should prevent double frees. */1898 Assert(pHstStream != pGstStream);1899 1900 if (pHstStream)1901 {1902 pHstStream->pPair = NULL;1903 RTListNodeRemove(&pHstStream->Node);1904 }1905 1906 if (pGstStream)1907 {1908 pGstStream->pPair = NULL;1909 RTListNodeRemove(&pGstStream->Node);1910 }1911 1912 if (pHstStream)1913 {1914 rc = drvAudioStreamDestroyInternal(pThis, pHstStream);1915 AssertRC(rc);1916 1917 pHstStream = NULL;1918 }1919 1920 if (pGstStream)1921 {1922 rc = drvAudioStreamDestroyInternal(pThis, pGstStream);1923 AssertRC(rc);1924 1925 pGstStream = NULL;1926 }1927 }1928 1929 if (RT_SUCCESS(rc))1930 {1931 if (enmDir == PDMAUDIODIR_IN)1932 {1933 pThis->cStreamsFreeIn++;1934 }1935 else /* Out */1936 {1937 pThis->cStreamsFreeOut++;1938 }1939 }1940 1941 int rc2 = RTCritSectLeave(&pThis->CritSect);1942 if (RT_SUCCESS(rc))1943 rc = rc2;1944 1945 LogFlowFuncLeaveRC(rc);1946 return rc;1947 }1948 1949 static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)1950 {1951 AssertPtrReturn(pThis, VERR_INVALID_POINTER);1952 AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);1953 1954 AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,1955 ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));1956 1957 int rc = VINF_SUCCESS;1958 1959 LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus));1960 1961 if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)1962 {1963 if (pThis->pHostDrvAudio)1964 rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);1965 if (RT_SUCCESS(rc))1966 pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;1967 }1968 1969 LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc));1970 return rc;1971 }1972 1973 static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)1974 {1975 AssertPtrReturn(pThis, VERR_INVALID_POINTER);1976 AssertPtrReturn(pStream, VERR_INVALID_POINTER);1977 1978 LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));1979 1980 if (pStream->cRefs > 1)1981 return VERR_WRONG_ORDER;1982 1983 int rc = VINF_SUCCESS;1984 1985 if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST)1986 {1987 if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)1988 {1989 rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);1990 if (RT_SUCCESS(rc))1991 pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;1992 }1993 }1994 else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)1995 {1996 rc = drvAudioStreamDestroyInternalBackend(pThis, pStream);1997 }1998 else1999 AssertFailedReturn(VERR_NOT_IMPLEMENTED);2000 2001 if (RT_SUCCESS(rc))2002 {2003 /* Destroy mixing buffer. */2004 AudioMixBufDestroy(&pStream->MixBuf);2005 2006 if (pStream)2007 {2008 RTMemFree(pStream);2009 pStream = NULL;2010 }2011 }2012 2013 LogFlowFunc(("Returning %Rrc\n", rc));2014 return rc;2015 }2016 2017 /********************************************************************/2018 2019 /**2020 * @interface_method_impl{PDMIBASE,pfnQueryInterface}2021 */2022 static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)2023 {2024 LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));2025 2026 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);2027 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);2028 2029 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);2030 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);2031 2032 return NULL;2033 }2034 2035 /**2036 * Power Off notification.2037 *2038 * @param pDrvIns The driver instance data.2039 */2040 static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)2041 {2042 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);2043 2044 LogFlowFuncEnter();2045 2046 /* Just destroy the host stream on the backend side.2047 * The rest will either be destructed by the device emulation or2048 * in drvAudioDestruct(). */2049 PPDMAUDIOSTREAM pStream;2050 RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)2051 drvAudioStreamDestroyInternalBackend(pThis, pStream);2052 2053 /*2054 * Last call for the driver below us.2055 * Let it know that we reached end of life.2056 */2057 if (pThis->pHostDrvAudio->pfnShutdown)2058 pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);2059 2060 pThis->pHostDrvAudio = NULL;2061 2062 LogFlowFuncLeave();2063 }2064 2065 /**2066 * Constructs an audio driver instance.2067 *2068 * @copydoc FNPDMDRVCONSTRUCT2069 */2070 static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)2071 {2072 LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));2073 2074 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);2075 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);2076 1600 2077 1601 /* … … 2095 1619 pThis->IAudioConnector.pfnStreamSetVolume = drvAudioStreamSetVolume; 2096 1620 pThis->IAudioConnector.pfnStreamPlay = drvAudioStreamPlay; 1621 pThis->IAudioConnector.pfnStreamCapture = drvAudioStreamCapture; 2097 1622 #ifdef VBOX_WITH_AUDIO_CALLBACKS 2098 1623 pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks; … … 2145 1670 int rc2 = RTCritSectEnter(&pThis->CritSect); 2146 1671 AssertRC(rc2); 1672 1673 PPDMAUDIOSTREAM pStream, pStreamNext; 1674 RTListForEachSafe(&pThis->lstHstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node) 1675 drvAudioStreamDestroyInternal(pThis, pStream); 1676 1677 RTListForEachSafe(&pThis->lstGstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node) 1678 drvAudioStreamDestroyInternal(pThis, pStream); 2147 1679 2148 1680 /* -
trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
r61332 r61523 94 94 void *pvBuf; 95 95 size_t cbBuf; 96 /** Minimum samples required for ALSA to play data. */ 97 uint32_t cSamplesMin; 96 98 } ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT; 97 99 … … 171 173 typedef struct ALSAAUDIOSTREAMCFG 172 174 { 173 unsigned int freq; 174 snd_pcm_format_t fmt; 175 int nchannels; 176 unsigned long buffer_size; 177 unsigned long period_size; 178 snd_pcm_uframes_t samples; 175 unsigned int freq; 176 /** PCM sound format. */ 177 snd_pcm_format_t fmt; 178 /** PCM data access type. */ 179 snd_pcm_access_t access; 180 /** Whether resampling should be performed by alsalib or not. */ 181 int resample; 182 int nchannels; 183 unsigned long buffer_size; 184 unsigned long period_size; 185 snd_pcm_uframes_t samples; 179 186 } ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG; 180 187 … … 348 355 } 349 356 357 err = snd_pcm_sw_params_set_avail_min(phPCM, pSWParms, 512); 358 if (err < 0) 359 { 360 LogRel(("ALSA: Failed to set available minimum to %ld: %s\n", 361 threshold, snd_strerror(err))); 362 rc = VERR_ACCESS_DENIED; 363 break; 364 } 365 350 366 err = snd_pcm_sw_params(phPCM, pSWParms); 351 367 if (err < 0) … … 385 401 return rc; 386 402 } 403 404 #if 0 /* After Beta. */ 405 static int alsaSetHWParams(snd_pcm_t *phPCM, PALSAAUDIOSTREAMCFG pCfg) 406 { 407 int rc; 408 snd_pcm_hw_params_t *pParams = NULL; 409 410 do 411 { 412 snd_pcm_hw_params_alloca(&pParams); 413 if (!pParams) 414 { 415 rc = VERR_NO_MEMORY; 416 break; 417 } 418 419 unsigned int rrate; 420 snd_pcm_uframes_t size; 421 int dir; 422 423 /* choose all parameters */ 424 int err = snd_pcm_hw_params_any(phPCM, pParams); 425 if (err < 0) 426 { 427 LogRel(("ALSA: Broken configuration for playback: no configurations available: %s\n", snd_strerror(err))); 428 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 429 break; 430 } 431 /* set hardware resampling */ 432 err = snd_pcm_hw_params_set_rate_resample(phPCM, pParams, pCfg->resample); 433 if (err < 0) 434 { 435 LogRel(("ALSA: Resampling setup failed for playback: %s\n", snd_strerror(err))); 436 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 437 break; 438 } 439 /* set the interleaved read/write format */ 440 err = snd_pcm_hw_params_set_access(phPCM, pParams, pCfg->access); 441 if (err < 0) 442 { 443 LogRel(("ALSA: Access type not available for playback: %s\n", snd_strerror(err))); 444 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 445 break; 446 } 447 /* set the sample format */ 448 err = snd_pcm_hw_params_set_format(phPCM, pParams, pCfg->fmt); 449 if (err < 0) 450 { 451 LogRel(("ALSA: Sample format not available for playback: %s\n", snd_strerror(err))); 452 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 453 break; 454 } 455 /* set the count of channels */ 456 err = snd_pcm_hw_params_set_channels(phPCM, pParams, pCfg->nchannels); 457 if (err < 0) 458 { 459 LogRel(("ALSA: Channels count (%d) not available for playbacks: %s\n", pCfg->nchannels, snd_strerror(err))); 460 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 461 break; 462 } 463 /* set the stream rate */ 464 rrate = pCfg->freq; 465 err = snd_pcm_hw_params_set_rate_near(phPCM, pParams, &rrate, 0); 466 if (err < 0) 467 { 468 LogRel(("ALSA: Rate %uHz not available for playback: %s\n", pCfg->freq, snd_strerror(err))); 469 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 470 break; 471 } 472 if (rrate != pCfg->freq) 473 { 474 LogRel(("ALSA: Rate doesn't match (requested %iHz, get %uHz)\n", pCfg->freq, err)); 475 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 476 break; 477 } 478 /* set the buffer time */ 479 err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pParams, &pCfg->buffer_time, &dir); 480 if (err < 0) 481 { 482 LogRel(("ALSA: Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err))); 483 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 484 break; 485 } 486 err = snd_pcm_hw_params_get_buffer_size(pParams, &size); 487 if (err < 0) 488 { 489 LogRel(("ALSA: Unable to get buffer size for playback: %s\n", snd_strerror(err))); 490 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 491 break; 492 } 493 buffer_size = size; 494 /* set the period time */ 495 err = snd_pcm_hw_params_set_period_time_near(phPCM, pParams, &period_time, &dir); 496 if (err < 0) 497 { 498 LogRel(("ALSA: Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err))); 499 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 500 break; 501 } 502 err = snd_pcm_hw_params_get_period_size(pParams, &size, &dir); 503 if (err < 0) 504 { 505 LogRel(("ALSA: Unable to get period size for playback: %s\n", snd_strerror(err))); 506 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 507 break; 508 } 509 period_size = size; 510 /* write the parameters to device */ 511 err = snd_pcm_hw_params(phPCM, pParams); 512 if (err < 0) 513 { 514 LogRel(("ALSA: Unable to set hw params for playback: %s\n", snd_strerror(err))); 515 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 516 break; 517 } 518 519 rc = VINF_SUCCESS; 520 521 } while (0); 522 523 if (pParams) 524 { 525 snd_pcm_hw_params_free(pParams); 526 pParams = NULL; 527 } 528 529 LogFlowFuncLeaveRC(rc); 530 return rc; 531 } 532 static int alsaSetSWParams(snd_pcm_t *phPCM, PALSAAUDIOCFG pCfg) 533 { 534 int rc; 535 snd_pcm_sw_params_t *pParams = NULL; 536 537 do 538 { 539 snd_pcm_sw_params_alloca(&pParams); 540 if (!pParams) 541 { 542 rc = VERR_NO_MEMORY; 543 break; 544 } 545 /* get the current swparams */ 546 int err = snd_pcm_sw_params_current(phPCM, pParams); 547 if (err < 0) 548 { 549 LogRel(("ALSA: Unable to determine current swparams for playback: %s\n", snd_strerror(err))); 550 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 551 break; 552 } 553 /* start the transfer when the buffer is almost full: */ 554 /* (buffer_size / avail_min) * avail_min */ 555 err = snd_pcm_sw_params_set_start_threshold(phPCM, pParams, (buffer_size / period_size) * period_size); 556 if (err < 0) 557 { 558 LogRel(("ALSA: Unable to set start threshold mode for playback: %s\n", snd_strerror(err))); 559 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 560 break; 561 } 562 /* allow the transfer when at least period_size samples can be processed */ 563 /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ 564 err = snd_pcm_sw_params_set_avail_min(phPCM, pParams, period_size); 565 if (err < 0) 566 { 567 LogRel(("ALSA: Unable to set avail min for playback: %s\n", snd_strerror(err))); 568 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 569 break; 570 } 571 /* write the parameters to the playback device */ 572 err = snd_pcm_sw_params(phPCM, pParams); 573 if (err < 0) 574 { 575 LogRel(("ALSA: Unable to set sw params for playback: %s\n", snd_strerror(err))); 576 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 577 break; 578 } 579 580 rc = VINF_SUCCESS; 581 582 } while (0); 583 584 if (pParams) 585 { 586 snd_pcm_sw_params_free(pParams); 587 pParams = NULL; 588 } 589 590 LogFlowFuncLeaveRC(rc); 591 return rc; 592 } 593 #endif 387 594 388 595 static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREAMCFG pCfgObt, snd_pcm_t **pphPCM) … … 614 821 } 615 822 823 LogFunc(("Buffer sample size is: %RU32\n", obt_buffer_size)); 824 616 825 snd_pcm_uframes_t obt_period_size; 617 826 int dir = 0; … … 983 1192 case 0: 984 1193 { 985 LogFunc(("Failed to write %R I32 frames\n", cRead));1194 LogFunc(("Failed to write %RU32 samples\n", cRead)); 986 1195 rc = VERR_ACCESS_DENIED; 987 1196 break; … … 1149 1358 1150 1359 if (pcSamples) 1151 *pcSamples = obt.samples ;1360 *pcSamples = obt.samples * 4; 1152 1361 } 1153 1362 while (0); … … 1445 1654 snd_pcm_sframes_t cAvail; 1446 1655 int rc2 = alsaStreamGetAvail(pStreamOut->phPCM, &cAvail); 1447 if ( RT_SUCCESS(rc2) 1448 && cAvail >= 1024) /** @todo !!! HACK ALERT !!! Use bufsize. */ 1656 if (RT_SUCCESS(rc2)) 1449 1657 { 1450 1658 LogFlowFunc(("cAvail=%ld\n", cAvail)); 1451 strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE; 1659 if (cAvail >= pStreamOut->cSamplesMin) 1660 strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE; 1452 1661 } 1453 1662 } -
trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
r61386 r61523 1417 1417 | PDMAUDIOSTRMSTS_FLAG_ENABLED; 1418 1418 1419 pa_threaded_mainloop_lock(pThis->pMainLoop); 1420 1419 1421 pa_context_state_t ctxState = pa_context_get_state(pThis->pContext); 1420 1422 … … 1422 1424 && pa_stream_get_state(pStrm->pPAStream) == PA_STREAM_READY) 1423 1425 { 1426 size_t cbSize; 1427 1424 1428 if (pStream->enmDir == PDMAUDIODIR_IN) 1425 1429 { 1426 1430 cbSize = pa_stream_readable_size(pStrm->pPAStream); 1431 1432 if (cbSize) 1433 strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE; 1427 1434 } 1428 1435 else 1429 1436 { 1430 size_t cbSize = pa_stream_writable_size(pStrm->pPAStream); 1431 LogFlowFunc(("cbSize=%zu\n", cbSize)); 1437 cbSize = pa_stream_writable_size(pStrm->pPAStream); 1432 1438 1433 1439 if (cbSize >= pStrm->BufAttr.minreq) 1434 {1435 1440 strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE; 1436 } 1437 } 1438 } 1441 } 1442 1443 LogFlowFunc(("cbSize=%zu\n", cbSize)); 1444 } 1445 1446 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1439 1447 1440 1448 return strmSts; -
trunk/src/VBox/Devices/Audio/alsa_mangling.h
r59987 r61523 56 56 #define snd_pcm_sw_params_current ALSA_MANGLER(snd_pcm_sw_params_current) 57 57 #define snd_pcm_sw_params_set_start_threshold ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold) 58 #define snd_pcm_sw_params_set_avail_min ALSA_MANGLER(snd_pcm_sw_params_set_avail_min) 58 59 59 60 #endif /* !AUDIO_ALSA_MANGLING_H */ -
trunk/src/VBox/Devices/Audio/alsa_stubs.c
r59987 r61523 116 116 (pcm, params)) 117 117 PROXY_STUB(snd_pcm_sw_params_set_start_threshold, int, 118 (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val), 119 (pcm, params, val)) 120 PROXY_STUB(snd_pcm_sw_params_set_avail_min, int, 118 121 (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val), 119 122 (pcm, params, val)) … … 162 165 ELEMENT(snd_pcm_sw_params_current), 163 166 ELEMENT(snd_pcm_sw_params_set_start_threshold), 167 ELEMENT(snd_pcm_sw_params_set_avail_min) 164 168 }; 165 169 #undef ELEMENT
Note:
See TracChangeset
for help on using the changeset viewer.

